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

如何使用Google Test测试调用私有void函数的公有void函数

用Google Test测试fun函数的方案

针对你的场景,要测试公有函数fun,核心是模拟依赖的外部对象m的行为,并验证私有成员函数funa/funb/func是否被正确调用,具体步骤如下:

1. 抽象依赖对象m的接口

首先假设m指向的是一个抽象基类(如果原本不是,建议重构为抽象类,这是可测试性的基础),示例定义:

class IMessageSource {
public:
    virtual ~IMessageSource() = default;
    virtual bool hasMessage() = 0;
    virtual std::pair<std::string, Vector> getMessage() = 0;
    virtual std::string MessageType(const auto& x) = 0; // 根据实际x的类型调整参数
};

你的业务类(假设名为MyClass)需持有该抽象类指针:

class MyClass {
public:
    explicit MyClass(IMessageSource* m) : m_(m) {}
    void fun(); // 被测公有函数
private:
    void funa(const auto& x, const std::string& topic);
    void funb(const auto& x, const std::string& topic);
    void func(const auto& x, const std::string& topic);
    IMessageSource* m_;
};

2. 用Google Mock创建IMessageSource的Mock类

通过Mock类模拟m的各种行为,控制测试流程:

#include <gmock/gmock.h>

class MockMessageSource : public IMessageSource {
public:
    MOCK_METHOD(bool, hasMessage, (), (override));
    MOCK_METHOD(std::pair<std::string, Vector>, getMessage, (), (override));
    MOCK_METHOD(std::string, MessageType, (const auto& x), (override)); // 匹配实际参数类型
};

3. 验证私有成员函数的调用

因为funa/funb/func是私有函数,有两种常用验证方式:

方式一:通过可测试子类暴露私有函数

创建MyClass的子类,将私有函数的调用记录下来,方便验证:

class TestableMyClass : public MyClass {
public:
    using MyClass::MyClass; // 继承构造函数
    // 记录funa的调用情况
    void funa(const auto& x, const std::string& topic) override {
        ++funa_call_count;
        last_funa_x = x;
        last_funa_topic = topic;
    }
    int funa_call_count = 0;
    decltype(auto) last_funa_x; // 匹配x的实际类型
    std::string last_funa_topic;

    // 同理为funb、func添加调用计数和参数记录字段
    int funb_call_count = 0;
    decltype(auto) last_funb_x;
    std::string last_funb_topic;

    int func_call_count = 0;
    decltype(auto) last_func_x;
    std::string last_func_topic;
};

注:如果原私有函数是虚函数,可直接用MOCK_METHOD创建Mock版本;非虚函数则用上述记录字段的方式。

方式二:验证私有函数的副作用

如果funa/funb/func执行会产生可观测的副作用(比如修改成员变量、调用外部接口),可直接验证这些副作用,无需检测函数本身的调用。

4. 编写具体测试用例

以下是几个典型测试场景的示例:

TEST(MyClassTest, CallsFunaWhenMessageTypeIsA) {
    // 1. 初始化Mock和测试类
    MockMessageSource mock_m;
    TestableMyClass my_class(&mock_m);
    Vector test_msg = {x_a}; // x_a为匹配Vector元素类型的测试数据
    std::string test_topic = "test_topic_a";

    // 2. 设置Mock行为:让循环执行一次后退出,返回指定消息和类型
    EXPECT_CALL(mock_m, hasMessage())
        .WillOnce(testing::Return(true))
        .WillOnce(testing::Return(false));
    EXPECT_CALL(mock_m, getMessage())
        .WillOnce(testing::Return(std::make_pair(test_topic, test_msg)));
    EXPECT_CALL(mock_m, MessageType(x_a))
        .WillOnce(testing::Return("a"));

    // 3. 执行被测函数
    my_class.fun();

    // 4. 验证结果:funa被调用一次,参数正确
    EXPECT_EQ(my_class.funa_call_count, 1);
    EXPECT_EQ(my_class.last_funa_x, x_a);
    EXPECT_EQ(my_class.last_funa_topic, test_topic);
}

TEST(MyClassTest, CallsFunbWhenMessageTypeIsB) {
    // 逻辑类似:设置MessageType返回"b",验证funb的调用计数和参数
}

TEST(MyClassTest, DoesNothingWhenNoMessages) {
    MockMessageSource mock_m;
    TestableMyClass my_class(&mock_m);
    EXPECT_CALL(mock_m, hasMessage())
        .WillOnce(testing::Return(false));
    
    my_class.fun();
    
    // 验证所有私有函数都未被调用
    EXPECT_EQ(my_class.funa_call_count, 0);
    EXPECT_EQ(my_class.funb_call_count, 0);
    EXPECT_EQ(my_class.func_call_count, 0);
}

关键注意事项

  • 如果m原本不是抽象类,优先重构为依赖抽象接口,这是实现可测试性的核心。
  • 若私有函数无法通过子类暴露,可考虑将这些函数提取到辅助类中,通过依赖注入的方式引入,再Mock辅助类验证调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:40:38