Corina David
Corina David

Reputation: 43

Mock for a concrete class using gmock in C++

I am stuck with creating a mock for a concrete class.

I know that is not a great idea to do this but I'm not not allowed to change production code.

My code is similar with:

Class A
{
public:
        A(B* b)
        {
                this->b = b;
        }
.........................
 void function_from_a_to_test(<arg>)
{
        if(!b)
                b->function_from_b();
        else
             //something to do
}
private:
        B * b;
};

class B
{
........
 public:       
        void function_from_b();
......
};
class MockB : public B , testing::Mock //i don't know why I can that, B is not virtual 
{

 MOCK_METHOD(function_from_b, void, (void));

};


A_Test :testing::Test{
 SetUp()
{
        b = new B();
        a = new A(b);
}

 TearDown()
{
        delete b ;
        delete a ;
}

void set_b(B * bb)
{
        a->b = bb;
}

.........................
}

In order to test I used Test_f

TEST_F(A_Test, Test_function_from_a_to_test)
{
//arrange

//act
 B * b_t = new MockB();
set_b(b_t);
EXPECT_CALL(*(static_cast<MockB> b_t), function_from_b))
        .Times(10);

function_from_a_to_test(arg);
}

It's seems that the test is passed but i got memory leak at static cast.

And If I store the result of static cast in another variable (in order to delete it), the expect call having that variable is failing.

I know that is not really a good practice, but I can not change the production code.

Has somebody a idea how to solve it? Or a better way to test this?

Upvotes: 3

Views: 2471

Answers (1)

Chris Olsen
Chris Olsen

Reputation: 3471

You can't mock a non-virtual function using inheritance. You would have to have to define a mock class that implements the functions needed by the code under test, and then have a way to replace the concrete class with the mock class. Read more about it here.

To be honest, I have no idea what the result of that static_cast is, but it's probably not good.

The only way I can think of to do what you want to do without changing production code is to use a different include path in your test project that would allow completely replacing the concrete class B with the mock class B. This may or may not be possible, depending on how your production code is structured.

If you're lucky enough to have class B defined in a separate header file, then it's easy: Make a mock header file with the same name but different folder, and make sure that folder appears in the include path before the production header file's location.

Production B.h file (in original location and unmodified):

class B
{
public:
    void function_from_b() {}
};

Mock B.h file (in test code location):

class B
{
public:
    MOCK_METHOD(void, function_from_b, ());
};

Somewhere in production code (unmodified):

#include "B.h" // Will load original or mock depending on include path

class A
{
public:
    A(B *b)
    {
        m_b = b;
    }

    void function_from_a_to_test(int arg)
    {
        if (m_b)
            m_b->function_from_b();
        else
            ;    //something to do
    }

private:
    B *m_b;
}

Test code:

TEST(A_Test, Test_function_from_a_to_test)
{
    B b;
    A a(&b);

    EXPECT_CALL(b, function_from_b)
        .Times(1);

    a.function_from_a_to_test(0);
}

Upvotes: 1

Related Questions