如何在单元测试中为EXPECT_CALL传入外部创建对象的引用?
问题描述
在单元测试中尝试用GMOCK的EXPECT_CALL模拟抽象类Handler的虚函数Foo,但该方法接收struct SomeStruct的const引用参数,而这个结构体是在Source::Bar()内部创建的,测试代码里拿不到同一个引用,导致出现GMOCK警告:
GMOCK WARNING:
Uninteresting mock function call - returning directly.
Function call: Foo
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.
相关代码如下:
struct SomeStruct { int a; }; class Handler { public: virtual void Foo(const SomeStruct&) = 0; }; class Source { std::weak_ptr<Handler> _handler; public: Source(std::weak_ptr<Handler> handler) : _handler(handler) {} void Bar() { SomeStruct s = {.a = 10}; // 内部创建的结构体 if (auto sp = _handler.lock()) { sp->Foo(s); // 需要模拟的调用 } } }; class MockHandler : public Handler { public: MOCK_METHOD(void, Foo, (const SomeStruct&), (override)); }; TEST_F(UtClass, TestSourceBar) { auto sp = std::make_shared<MockHandler>(); SomeStruct s = {.a = 10}; // 这里传入的s和Bar内部的s不是同一个引用,直接用会不匹配 //EXPECT_CALL(*sp, Foo(s)).WillRepeatedly(Return()); Source source (sp); source.Bar(); }
解决方案
GMOCK提供多种匹配器解决这类无法直接传入相同引用的场景,常用方案如下:
1. 用Eq()匹配器验证结构体内容
如果SomeStruct支持相等比较(默认成员逐一比对即可),可以用Eq()匹配器验证传入的结构体内容是否符合预期,无需引用相同对象:
TEST_F(UtClass, TestSourceBar) { auto sp = std::make_shared<MockHandler>(); SomeStruct expected_s = {.a = 10}; // 匹配内容相等的SomeStruct对象 EXPECT_CALL(*sp, Foo(Eq(expected_s))).Times(1); Source source(sp); source.Bar(); }
如果SomeStruct默认不支持==运算符,需手动重载:
bool operator==(const SomeStruct& lhs, const SomeStruct& rhs) { return lhs.a == rhs.a; }
2. 用字段匹配器Field()验证特定成员
若只需验证结构体的某个成员值,可直接用Field()匹配器,无需重载相等运算符:
TEST_F(UtClass, TestSourceBar) { auto sp = std::make_shared<MockHandler>(); // 验证传入的SomeStruct的a成员等于10 EXPECT_CALL(*sp, Foo(Field(&SomeStruct::a, 10))).Times(1); Source source(sp); source.Bar(); }
3. 自定义匹配器实现复杂验证
如果需要更复杂的验证逻辑,可自定义匹配器:
MATCHER_P(SomeStructMatchesA, expected_a, "") { return arg.a == expected_a; } TEST_F(UtClass, TestSourceBar) { auto sp = std::make_shared<MockHandler>(); // 使用自定义匹配器验证a的值 EXPECT_CALL(*sp, Foo(SomeStructMatchesA(10))).Times(1); Source source(sp); source.Bar(); }
4. 忽略参数(谨慎使用)
如果不需要验证SomeStruct参数,仅需确保Foo被调用,可用_匹配器忽略参数:
TEST_F(UtClass, TestSourceBar) { auto sp = std::make_shared<MockHandler>(); // 忽略参数,仅验证调用次数 EXPECT_CALL(*sp, Foo(_)).Times(1); Source source(sp); source.Bar(); }
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

