How do you create Mock Objects with gMock?
Asked Answered
D

2

7

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.

Davidadavidde answered 4/3, 2020 at 7:52 Comment(0)
B
6

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);
}
Bertie answered 4/3, 2020 at 16:30 Comment(2)
Thank you! Dependency Injection is exactly the Keyword I needed. I'm relatively new to programming so this is very helpful advice!Davidadavidde
In case anyone is looking for the Gmock for dummies document, it has moved.Scarecrow
B
0

You are missing quite a few things unless you are not putting them here. Read slowly the documentation of the googletests and specifically the mocks. This is how I usually define the mocks:

#include <gmock/gmock.h>
#include "Foo.hpp"

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

You need to write the number of arguments of the methods after the expression MOCK_METHOD, then the return type and between parenthesis the types of the arguments. If you don't want to worry about this use this nice generator that is in the library.

Then in the tests itself is where you define the behavior of the mock, that is the point of it, you can do a general definition for all the tests or change it in some to work differently.

I think it doesn't make sense to write a full example because you have in the tutorials really good and simple ones, so check it.

Bara answered 4/3, 2020 at 10:33 Comment(2)
Yes, you are right, it's probably better to define the Mock Methods like that, but this doesn't really matter because I'm not sure if this is even the right approach. My Problem is: I have a method and this method calls a function of another class, which is not virtual. Now how do I test this. The tutorial in the documentation just shows it for abstract classes. That's why I tried this approach with the parent class Foo.Davidadavidde
MOCK_METHOD without parameter count is the preferred method in the latest gMock releases. MOCK_METHOD<N> is the old style.Bertie

© 2022 - 2024 — McMap. All rights reserved.