Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to GMOCK a function within function?

I have a function1 inside which function 2 is called. I have to mock only function2, whwenever i call function1 it should call real implementation of function1 and mock implementation of function2. Kindly help me on this

Display.cpp

    #include "Display.h"
int DisIp::getip()
{

return 5;

}
int  DisIp::display()
{
        Addition obj;
        int ip=obj.getip();
    return ip;
}

Display.h

class DisIP
{
public:
    int display();
        int getip();
};

GMOCK file

#include <limits.h>
#include "gmock.h"
#include "gtest.h"
#include "Display.h"
#include <string>
using namespace std;
using ::testing::AtLeast;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Gt;
using ::testing::Return;
using testing::ReturnPointee;
using ::testing::Invoke;
class MyInterface{
public:

    virtual int display() = 0;
    virtual int getip()=0;
};

class MockInter : public MyInterface
{
public:
MockInter()
{
        ON_CALL(*this, getip()).WillByDefault(Invoke(&this, &MockInter::getip));
        ON_CALL(*this, display()).WillByDefault(Invoke(&real, &Addition::display));
}
MOCK_METHOD0(display,int());
MOCK_METHOD0(getip,int());
DisIp real;
};


class DisplayTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

  virtual void TearDown() {
    // Code here will be called immediately after each test
    // (right before the destructor).
  }
};

TEST_F(DisplayTest,ip){
        MockInter mock;
//EXPECT_EQ(1,mock.display());
EXPECT_EQ(1,mock.getip());
}
like image 442
Prasanth Manoharan Avatar asked Nov 21 '25 07:11

Prasanth Manoharan


1 Answers

Your design suffers from breaking Single Responsibility Principle.

Displaying and getting IP are two different responsibilities. It is even shown in your implementation of DisIp::display() - you get IP from so-called Addition obj. When you fix this design error - your unit tests becomes much easier and straightforward. But it is important to say that UT are only the symptom here, the bad design is a disease.

So how it could look like:

class IIpProvider
{
public:
  virtual ~IIpProvider() = default;
  virtual int getIp() = 0;
};

class DispIp
{
public:
    DispIp(IIpProvider& ipProvider) : ipProvider(ipProvider) {}
    int display()
    {
       int ip=ipProvider.getIp();
       //...
       return ip;
    }
private:
   IIpProvider& ipProvider;
};

then your Mock:

class IpProviderMock : public IIpProvider
{
public:
  MOCK_METHOD0(getIp, int());
};

And your tests:

class DispIpTest : public ::testing::Test
{
protected:
   IpProviderMock ipProviderMock;
   DispIp objectUnderTest{ipProviderMock}; // object-under-test must be connected to object doubles (like mocks)
};
TEST_F(DispIpTest, shallUseProvidedIpToDisplay)
{
    using namespace testing;
    auto SOME_IP = 7;
    EXPECT_CALL(ipProviderMock, getIp()).WillRepeatedly(Return(SOME_IP));
    //...
    ASSERT_EQ(SOME_IP, objectUnderTest.display());
}

In your original tests - main problem was also that your mock object was not connected in any way to your object under test.


If you do not like (cannot) to change your design (what I really advice) you have to use technique called partial mocking

In your case - it would something like this:

class DisIP
{
public:
    int display();
    virtual int getip(); // function for partial mocking must be virtual
};
class DisIPGetIpMock : public DisIP
{
public:
      MOCK_METHOD0(getIp, int());
};
class DispIpTest : public ::testing::Test
{
protected:
   DisIPGetIpMock objectUnderTest; 
};

TEST_F(DispIpTest, shallUseProvidedIpToDisplay)
{
    EXPECT_CALL(objectUnderTest, getIp()).WillRepeatedly(Return(SOME_IP));
    ...
    ASSERT_EQ(SOME_IP, objectUnderTest.display());
}
like image 145
PiotrNycz Avatar answered Nov 22 '25 20:11

PiotrNycz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!