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

如何在单元测试中为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:45:39