Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a member variable of dependency?

I've got a class and member:

class A
{
    B obj;
public:
    int f(int i){return obj.g(i);}
}

Here B obj is a dependency that requires run-time creation from a file. In my unit test for class A, I wish to mock B obj, with a function g typed int(int).

How can I write my test code, to mock B obj, and then test A::f.

Thanks a lot.

like image 793
Hind Forsum Avatar asked Sep 03 '25 02:09

Hind Forsum


2 Answers

You need to use dependency injection to achieve this. To this end, have class B inherit from an interface, and have class A hold a pointer to that interface:

class IB
{
public:
    virtual void g(int i) = 0;
};

class B : public IB
{
public:
    void g(int i) {
        // this is your real implementation
    }
};

Also, to enable dependency injection in class A, add appropriate constructor or setter method:

class A
{
private:
    IB *obj;
public:
    A() : obj(nullptr) {}
    // You don't need both the constructor and setter, one is enough
    A(IB *pB) : obj(pB) {}
    // void setB(IB *pB) { obj = pB; }
    int f(int i) { return obj->g(i); }
};

Now, in your production code you create an object of class B and pass it to class A object (assuming that we are using the constructor for injection):

B b;
A a(&b);

During testing phase, you create a mock class BMock and pass an object of that class to class A object:

class BMock : public IB
{
public:
    MOCK_METHOD1(g, int(int));
};

TEST(ATests, TestCase1)
{
    BMock bmock;
    A a(&bmock);

    // Now you can set expectations on mock object, for example that g will
    // return 100 when it receives 50 as argument
    EXPECT_CALL(bmock, g(50)).WillOnce(Return(100));

    // Now act by calling A::f, which will in turn call g from mock object, 
    // and assert on function return value

    ASSERT_EQ(a.f(50), 100);
}
like image 122
Marko Popovic Avatar answered Sep 04 '25 16:09

Marko Popovic


You can't do it with the code you have. You have hardcoded your dependency inside the A class. To make mocking possible you have to use some of the dependency injection patterns. One of the possible ways is to have a pointer(better smart) to your B class and in the A constructor you will get a pointer to B with which you will initialize your inner B*. That way you will be able to put a mocked object in your tests.

like image 33
ixSci Avatar answered Sep 04 '25 15:09

ixSci