如何用Gmock模拟DLL函数?DllLoader模拟调用异常问题求解
解决DllLoader模拟测试时调用函数异常的问题
错误原因分析
你遇到的异常主要来自这几个问题:
- fun1是函数指针成员而非虚函数:gmock的
MOCK_METHOD只能模拟虚函数,原DllLoader中的fun1是一个函数指针变量,SomeClass调用的是基类的空指针(基类构造传空字符串导致LoadLibrary失败,fun1未赋值),根本不会触发Mock的方法,直接触发空指针异常。 - Mock类构造语法错误:
MockDllLoader() : DllLoader("");末尾应该用大括号而非分号,属于语法错误。 - 测试代码拼写错误:
new MocDllLoader()少写了一个k,应为MockDllLoader。
解决方案
要让gmock正确模拟,核心是让fun1成为可被多态覆盖的虚函数,或通过抽象接口解耦依赖。
方案一:修改DllLoader为可Mock结构
重构原DllLoader,把直接暴露的函数指针封装成虚成员函数:
typedef int(*fun_ptr)(int); class DllLoader { public: DllLoader(const std::string& dll_name) : handle(nullptr), fun1_ptr(nullptr) { handle = ::LoadLibraryA(dll_name.c_str()); if (handle) { fun1_ptr = reinterpret_cast<fun_ptr>(GetProcAddress(handle, "DLLFunction1")); } } // 虚析构函数,确保子类析构逻辑正确执行 virtual ~DllLoader() { if (handle) { ::FreeLibrary(handle); } } // 封装为虚函数,供Mock类覆盖 virtual int fun1(int param) { if (fun1_ptr) { return fun1_ptr(param); } throw std::runtime_error("DLL function not initialized"); } private: HMODULE handle; // LoadLibrary返回HMODULE语义更准确,与HANDLE是typedef关系 fun_ptr fun1_ptr; };
编写正确的Mock类:
#include <gmock/gmock.h> class MockDllLoader : public DllLoader { public: // 传入空字符串跳过实际DLL加载,Mock会覆盖fun1逻辑 MockDllLoader() : DllLoader("") {} // 用override明确标记覆盖虚函数,避免拼写错误 MOCK_METHOD(int, fun1, (int), (override)); };
修正后的测试代码:
TEST(SomeClassTest, TestInit) { // 用智能指针管理对象,避免内存泄漏 auto mock_dll = std::make_unique<MockDllLoader>(); SomeClass some_class(mock_dll.get()); // 期望调用fun1(100)时返回1000 EXPECT_CALL(*mock_dll, fun1(100)) .WillOnce(testing::Return(1000)); EXPECT_NO_THROW(some_class.init()); }
方案二:适配器模式(不修改原有DllLoader)
如果无法修改原DllLoader代码,可以新增抽象接口解耦依赖:
// 定义抽象接口 class IDllInterface { public: virtual ~IDllInterface() = default; virtual int fun1(int param) = 0; }; // 让原DllLoader适配到抽象接口 class DllLoaderAdapter : public IDllInterface { public: DllLoaderAdapter(const std::string& dll_name) : loader(dll_name) {} int fun1(int param) override { return loader.fun1(param); } private: DllLoader loader; }; // Mock类实现抽象接口 class MockDllLoader : public IDllInterface { public: MOCK_METHOD(int, fun1, (int), (override)); }; // 修改SomeClass依赖抽象接口而非具体类 class SomeClass { public: SomeClass(IDllInterface* dll) : dll(dll) {} void init() { int res = dll->fun1(100); // 原有业务逻辑 } private: IDllInterface* dll; };
测试代码与方案一一致,只需依赖IDllInterface即可完成Mock测试。
内容的提问来源于stack exchange,提问作者Shreya Acharya
相关产品推荐
相关产品推荐

