You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:05:13