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?
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.