Google Mock: Is it ok to use global mock objects?
Asked Answered
S

3

6

In all the documentation about gmock I always find the mock object to be instantiated inside a test, like that:

TEST(Bim, Bam)
{
    MyMockClass myMockObj;
    EXPECT_CALL(MyMockObj, foo(_));
    ...
}

So, the object is created and destroyed per test. I believe it's also perfectly fine to create and destroy the object per test fixture. But I'm wondering if it's also ok to have a file-global instance of the mock object, like that:

MyMockClass myMockObj;

TEST(Bim, Bam)
{
    EXPECT_CALL(MyMockObj, foo(_))
    ...
}

I tried it and I have absolutely no problems so far, it all seems to work fine. But maybe I should be aware of anything? Just because I stumbled about this question, where the only answer states:

... the problem is that you're instantiating a global instance of FooMock. Googlemock/googletest expect the mock to be defined either within the body of the test, or within a test fixture class.

But I could not find anything in the documentation or anywhere else that confirms this (did I overlook it?).

Thanks, Georg

PS: The reason why I need to use a global mock instance would be the topic of another discussion (see this posting of mine).

Sewer answered 28/8, 2015 at 8:29 Comment(0)
M
4

You can, but it is not a good idea.

Doing such a thing is violate the isolation principle of UT. This violation may cause an unexpected failure/pass in your tests.

Gtest uses the destructor of the fake objects to verify that the expectation occurred, this is the reason behind the expectation that each fake object will create and release in the body of the test, or within a test fixture class.

If you make the fake object global then it won't release at the end of each UT, then the verification won't execute and the test will pass even when it should fail. more over some of your UTs may fass/fail when you execute all your tests together; in one test you expect the method x won't call and in the other you expect that the method will call; in one UT you expect the method x will call 3 times, but the method was call twice in the test + one in other test(the test should fail but it won't...)

So the bottom line you should never use a global mock unless this global mock is being in use only to prevent null pointer(you didn't set a behaviour..)

Maidenhead answered 5/9, 2015 at 21:56 Comment(0)
O
2

Just stumbled across this question while chasing a bug related to my mock objects. In my case the problem was that the mock object's constructor was being called before InitGoogleMock, and that seemed to send things off into the weeds.

Note: I'm using Google Mock with CppUnitTestFramework.

Fail:

MockObject mock;
TEST_MODULE_INITIALIZE(ModuleInitialize)
{
    InitGoogleMock(argc, argv);
}

Win:

MockObject *mock = nullptr;
TEST_MODULE_INITIALIZE(ModuleInitialize)
{
    InitGoogleMock(argc, argv);
    mock = new MockObject;
}

TEST_MODULE_CLEANUP(ModuleCleanup)
{
    delete mock;
}

Not saying it's best practice or anything, but if you need global mock objects I'd say pay attention to when your constructors are being called.

Olaolaf answered 19/4, 2018 at 23:39 Comment(1)
Actually, that was pretty my solution which I also used in the end (except for using a std::unique_ptr). But thanks for your answer, which may be helpful for others!Sewer
C
1

In addition to the accepted answer, if you're using GTest, global variables will also be tagged as leakage when they're not destroyed after test cases are executed. The idea behind leakage is in this reference: https://google.github.io/googletest/gmock_cook_book.html#forcing-a-verification

If you don't want manual verification, the closest solution would be to have the mock object as a member of your fixture class. And if for some reason you would need to dynamically allocate mock, you can have a pointer and create/destroy the instance on SetUp and TearDown (the same concept as @Chris Olsen's answer). Or if you're in C++11, you can use shared_ptr:

class Fixture : public ::testing::Test 
{  
    std::shared_ptr<ObjT> mPtr;
    ...
    void SetUp()
    {
        mPtr = std::make_shared<ObjT>();
    }
    ...
}
Coraliecoraline answered 13/8, 2019 at 23:15 Comment(1)
Mayb I ask why you recommend to use shared_ptr? I would assume that you always just have one instance, so unique_ptr would fit better from my understanding. You probably even want to avoid that someone dublicates this shared_ptr(e.g. in a global variable, people go crazy sometimes), because it would mean that the ObjT-object will not be destroyed when the TEST_F is finished.Aggrade

© 2022 - 2024 — McMap. All rights reserved.