Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create Mock Objects with gMock?

So I am trying to learn how to write unit Tests and i stumbled upon the problem, that I don't understand how to create mock objects. Here's my example: I have this class:

class FooChild
{
public:
    void doThis();
    bool doThat(int n, double x);
};

And this is a method in another class I want to test:

#include "FooFighter.h"
#include "FooChild.h"

void FooFighter::doSomething()
{
    FooChild fooChild;
    fooChild.doThis();
    fooChild.doThat(4, 5);
}

I want to test Things like if it called the method and how many times. The Google mock documentary says, that only Abstract classes with virtual methods can be mocked. That's why i tried to create a parent class of FooChild, like this:

class Foo
{
public:
    virtual void doThis() = 0;
    virtual bool doThat(int n, double x) = 0;
};

And then create a mock class of Foo like this:

#include "gmock/gmock.h"

class MockFoo : public Foo
{
public:
    MOCK_METHOD(void, doThis, (), (override));
    MOCK_METHOD(bool, doThat, (int n, double x), (override));
};

Then I tried to write the Test for doSomething:

TEST_F(FooFighterTest, doSomethingTest)
{
    MockFoo mock_foo
    mock_foo.doThis()
        .Times(1);
}

Clearly this doesn't work and I have the feeling that I completely misunderstood how mocks work, but I just can't seem to find a nice and simple explanation on how to create mocks. Any help or advice would be great. Also my approach on how to test void functions like this might be completely wrong, so any advice on how to test functions that don't return anything would be great too.

like image 235
JLeon Avatar asked Aug 06 '26 04:08

JLeon


1 Answers

Your example is not too far off from working. You would probably find it helpful to read the gMock for Dummies document. It gives a good overview of the basics.

Essentially mocks allow you to set expectations on them, and verify that the expectations were met. You can also do things like control return values of mocked methods. Mocked methods must be virtual, but there is no requirement that they be abstract.

class FooChild
{
public:
    virtual void doThis() {}
    virtual bool doThat(int n, double x) { return false; }
};

class MockFooChild : public FooChild
{
public:
    MOCK_METHOD(void, doThis, (), (override));
    MOCK_METHOD(bool, doThat, (int n, double x), (override));
};

The biggest problem with in your example is that FooFighter::doSomething is using the concrete (real) class FooChild. You will need a way to substitute the the concrete class with the mocked class (using some form of dependency injection). Here's a simple example:

class FooFighter
{
public:
    void doSomething(FooChild &fooChild)
    {
        fooChild.doThis();
        fooChild.doThat(4, 5);
    }
};

Now you can test that FooFighter::doSomething is doing what it is expected to:

TEST(FooFighterTest, doSomethingTest)
{
    MockFooChild mockFooChild;
    FooFighter fooFighter;

    // doThis() must be called exactly 1 time.
    EXPECT_CALL(mockFooChild, doThis).Times(Exactly(1));

    // doThat() must be called exactly 1 time with parameters 4,5
    EXPECT_CALL(mockFooChild, doThat(4,5)).Times(Exactly(1));

    fooFighter.doSomething(mockFooChild);
}
like image 52
Chris Olsen Avatar answered Aug 07 '26 23:08

Chris Olsen