使用gtest与gmock_global Mock C++类方法中调用的全局函数
解决类方法内部调用的全局函数Mock问题
问题核心:你的测试代码中Mock了全局函数foo(),但Bar::buildBarStr()仍然调用原系统函数,原因是编译链接时Bar类绑定的是原全局foo的符号,而非Mock版本。以下是几种可行的解决方案:
方案一:预处理宏切换实现(无需修改生产代码结构)
在生产代码的foo定义处添加编译宏判断,测试环境下将foo声明为外部符号,让链接器指向Mock版本:
生产代码中修改foo的定义:
#ifndef TEST_BUILD int foo(){ return some_sys_parametr; } #else // 测试环境下仅声明foo,由gmock_global提供实现 extern int foo(); #endif
测试代码中添加宏定义:
在测试文件开头或编译选项中添加#define TEST_BUILD,确保编译测试代码时使用Mock的foo:
#define TEST_BUILD #include "gmock/gmock.h" #include "gmock_global/gmock_global.h" #include "Bar.h" 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; // 输出1 std::cout << "Test in obj call: " << test_obj.buildBarStr() << std::endl; // 输出Mock值1 }
方案二:利用Weak符号覆盖(GCC/Clang环境)
将原全局函数foo声明为Weak符号,这样测试代码中Mock的强符号会在链接时覆盖原函数:
生产代码中修改foo的声明:
// 声明为Weak符号,允许被强符号覆盖 __attribute__((weak)) int foo(); int foo(){ return some_sys_parametr; }
测试代码无需额外修改,保持你原有的Mock代码即可:
编译测试程序时,链接器会优先使用gmock_global生成的强符号foo,替换原Weak版本,此时Bar::buildBarStr()会调用Mock的foo。
方案三:依赖注入重构(更符合测试设计原则)
如果允许修改生产代码,将全局函数封装为抽象接口,通过依赖注入让Bar类依赖接口而非具体全局函数,这样测试时直接Mock接口即可:
1. 定义抽象接口
class SysParamInterface { public: virtual ~SysParamInterface() = default; virtual int getFoo() const = 0; };
2. 生产环境实现
class RealSysParam : public SysParamInterface { public: int getFoo() const override { return some_sys_parametr; } }; // 全局默认实例(兼容原有调用逻辑) static RealSysParam g_real_sys_param; SysParamInterface& g_sys_param = g_real_sys_param;
3. 修改Bar类依赖接口
class Bar{ private: const SysParamInterface& param_interface_; public: // 构造函数注入,默认使用全局实例 Bar(const SysParamInterface& param_interface = g_sys_param) : param_interface_(param_interface) {} std::string buildBarStr(){ std::string ans; int some_param = param_interface_.getFoo(); // some code return ans; } };
4. 测试时Mock接口
#include "gmock/gmock.h" class MockSysParam : public SysParamInterface { public: MOCK_METHOD(int, getFoo, (), (const, override)); }; TEST_F(FoobBarTest, FooBar) { MockSysParam mock_param; Bar test_obj(mock_param); ON_CALL(mock_param, getFoo()).WillByDefault(Return(1)); EXPECT_CALL(mock_param, getFoo()).Times(2); std::cout << "Test in obj call: " << test_obj.buildBarStr() << std::endl; // 输出Mock值1 }
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

