如何使用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
相关产品推荐
相关产品推荐

