c++mockinggoogletest

C++/Glolbal_Mock: How to mock a global function, which one calls in class method?


Have a next case.
Unit test instruments: gtest and gmock_global
Lng: C++.

First: we have a global function, which one returns some sys parameter like

int foo(){
    return some_sys_parametr;
}

Second: This function calls in some class method

class Bar{
public:
    std::string buildBarStr(){
        std::string ans;
        int some_param = foo();
        //some code
        return ans;
    }
};

For test case I don't want init third party library, so I decide to mock call of global function foo() with gmock_global. Example:

MOCK_GLOBAL_FUNC0(foo, int(void));
TEST_F(FoobBarTest, FooBar)
{
    Bar test_obj;
    ON_GLOBAL_NICE_CALL(foo, foo()).WillByDefault(Return(1));
    EXPECT_GLOBAL_CALL(foo, foo()).Times(2);
    std::cout << "Test call ret: " << foo() << std::endl; //Print 1, cause we make mock call
    std::cout << "Test in obj call: " << test_obj.buildBarStr() << std::endl;// Try to print some_sys_parametr, but I need mock answer 1 
}

So how to mock inner call of function in class method?


Solution

  • In the general case, it is not possible to mock global function in C++. Consider the header that is included by your class Bar implementation (let's say in Bar.cpp):

    // foo.hpp
    int foo() {
      return 3;
    }
    

    Now there is no way to hack it around and tell gtest/gmock that some different foo implementation should be used inside your buildBarStr. Compiler is even allowed to inline the call to foo inside buildBarStr and directly write 3 to some_param.

    If by chance, foo.hpp only contains the function declaration, and the definition is in foo.cpp, then you might work it around by not linking your test executable with foo.o (let's assume that at some point your build system produced g++ -c foo.cpp -o foo.o), and providing mock implementation. Then mock implementation can be: direct int foo definition in your tests, call to MOCK_GLOBAL_FUNC0, or link with some mockFoo.o object.

    But ... in serious projects you never have this kind of granular control over the single objects contributing to the final executable. Usually you would write

    add_library(Bar bar.cpp foo.cpp)
    

    to have the library containing your production logic, and then

    target_link_libraries(unittests Bar)
    

    which already links against int foo symbol in your Bar library. No amount of gmock-global magic will help you here, you will either end up with compiler error about multiple definitions, or linker error about multiple definitions. If you have static libraries, you could prepend the library with mocked foo, but IMHO it's a very fragile assumption.

    The proper way to make the code testable is to use dependency injection, like in gmock Cookbook example.