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

C++ GoogleTest测试调用单例的类:Mock方法未执行问题

在GoogleTest中解决单例依赖Mock失效问题

核心问题出在单例初始化时机与Mock对象替换时机不匹配,导致测试时调用的是原始MockedUtil实例而非你Mock的版本。以下是无需依赖注入的解决方案:

1. 给MockedUtil单例添加测试替换接口

对原单例做最小改动,保留原有逻辑的同时支持测试时替换实例:

// MockedUtil.h
class MockedUtil {
private:
    static MockedUtil* instance_;
    MockedUtil() = default; // 私有构造
public:
    static MockedUtil& GetInstance() {
        if (!instance_) {
            instance_ = new MockedUtil();
        }
        return *instance_;
    }

    // 测试专用:替换单例实例
    static void SetInstanceForTest(MockedUtil* mock_instance) {
        delete instance_;
        instance_ = mock_instance;
    }

    // 必须声明为虚函数,否则GoogleMock无法覆盖行为
    virtual bool readJSONFile(const std::string& path) {
        // 原始实现
        return false;
    }
};

2. 编写Mock类并在测试中替换单例

用GoogleMock创建MockedUtil的子类,在测试用例初始化阶段替换单例:

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "MockedUtil.h"
#include "ConcreteSingleton.h"
#include "ClassToBeTested.h"

class MockMockedUtil : public MockedUtil {
public:
    MOCK_METHOD(bool, readJSONFile, (const std::string& path), (override));
};

TEST(ClassToBeTestedTest, FooReachesCoveredLine) {
    // 创建Mock实例并替换单例
    auto mock_util = new MockMockedUtil();
    MockedUtil::SetInstanceForTest(mock_util);

    // 设置预期行为:调用readJSONFile时返回true
    EXPECT_CALL(*mock_util, readJSONFile(testing::_))
        .WillOnce(testing::Return(true));

    // 重置ConcreteSingleton,确保它获取Mock后的MockedUtil实例
    ConcreteSingleton::ResetForTest();

    // 执行测试逻辑
    ClassToBeTested tested_obj;
    tested_obj.foo();

    // 验证预期分支是否执行(比如断言分支对应的状态/输出)
    // ASSERT_TRUE(tested_obj.GetBranchExecutionFlag());

    // 清理:恢复原始单例,避免影响其他测试
    ConcreteSingleton::ResetForTest();
    MockedUtil::SetInstanceForTest(nullptr);
}

3. 给ConcreteSingleton添加重置接口

如果ConcreteSingleton在测试前已初始化并持有原始MockedUtil实例,需添加重置方法让它重新获取Mock后的实例:

// ConcreteSingleton.h
class ConcreteSingleton {
private:
    static ConcreteSingleton* instance_;
    MockedUtil& util_;
    ConcreteSingleton() : util_(MockedUtil::GetInstance()) {}
public:
    static ConcreteSingleton& GetInstance() {
        if (!instance_) {
            instance_ = new ConcreteSingleton();
        }
        return *instance_;
    }

    // 测试专用:重置单例
    static void ResetForTest() {
        delete instance_;
        instance_ = nullptr;
    }

    bool readJSON(const std::string& path) {
        return util_.readJSONFile(path);
    }
};

关键注意事项

  • 初始化顺序:必须在ConcreteSingleton初始化前替换MockedUtil单例,否则后者会持有原始实例。
  • 测试隔离:每个测试用例结束后重置单例,避免不同测试的状态污染。
  • 虚函数要求:MockedUtil的readJSONFile必须是虚函数,这是GoogleMock覆盖方法的前提。

内容的提问来源于stack exchange,提问作者roschach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:02:43