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

GoogleMock如何按顺序匹配重复调用?编译错误解析

GoogleMock 顺序匹配重复调用问题与编译错误解决

问题背景

我在使用GoogleMock编写单元测试时,遇到了重复调用按逆序匹配的问题,同时尝试绑定序列时出现编译错误。

初始测试代码如下:

TEST_F(at_operator_selection_tests, select_operators_selects_operator_with_best_signal)
{
    // arrange
    InSequence s;

    // 预期exp#1
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).WillOnce(Return(true));
    // 此处省略其他预期

    // 预期exp#2
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).WillOnce(Return(true));
    // 此处省略其他预期

    _at_protocol_mock.select_operator(some_var, another_var); // 匹配exp#2
    _at_protocol_mock.select_operator(some_var, another_var); // 再次匹配已饱和的exp#2
}        

根据GoogleMock的规则,相同签名的预期会按逆序匹配,导致exp#1永远不会被触发,exp#2被重复调用直至饱和。

改用Times(2)的方式虽然能解决重复调用问题,但在存在其他交错预期的场景下,无法清晰表达“第一次调用对应A逻辑,第二次对应B逻辑”的意图:

TEST_F(at_operator_selection_tests, select_operators_selects_operator_with_best_signal)
{
    // arrange
    InSequence s;

    // 合并为一个预期,无法区分两次调用的不同逻辑
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).Times(2).WillOnce(Return(true));
    // 此处省略其他预期

    _at_protocol_mock.select_operator(some_var, another_var);
    _at_protocol_mock.select_operator(some_var, another_var);
}  

尝试手动绑定序列时出现编译错误:

TEST_F(at_operator_selection_tests, select_operators_selects_operator_with_best_signal)
{
    // arrange
    InSequence s;

    // 预期exp#1 - 编译错误位置
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).Times(1).WillOnce(Return(true)).InSequence(s);
    // 此处省略其他预期

    // 预期exp#2
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).Times(1).WillOnce(Return(true)).InSequence(s);
    // 此处省略其他预期

    _at_protocol_mock.select_operator(some_var, another_var);
    _at_protocol_mock.select_operator(some_var, another_var);
 }

错误信息:

/home/bp/dev/iobox/firmware/unit_tests/source/valinso/modules/at/operator_selection_tests.cpp:216:104: error: no matching function for call to ‘testing::internal::TypedExpectation<bool(const etl::string<40>&, unsigned char)>::InSequence(testing::InSequence&)’
  216 |         EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).Times(1).WillOnce(Return(true)).InSequence(s);

需求:实现第一次调用匹配exp#2,第二次匹配exp#1的顺序匹配,并理解编译错误的原因。

编译错误原因

你混淆了InSequence和Sequence的用法:

  • InSequence是一个作用域对象,它会让其作用域内所有后续的EXPECT_CALL自动按顺序执行,不需要显式调用.InSequence()方法。
  • .InSequence()方法需要接收的是Sequence对象(而非InSequence对象),Sequence是用来手动分组预期到特定序列的工具。

你的代码中用InSequence对象作为.InSequence()的参数,导致类型不匹配,触发编译错误。

解决方案

要实现相同签名调用的顺序匹配,有两种可靠方法:

方法1:使用Sequence对象手动绑定预期

定义Sequence对象,然后将每个预期绑定到该序列,强制按声明顺序匹配:

TEST_F(at_operator_selection_tests, select_operators_selects_operator_with_best_signal)
{
    // arrange
    Sequence seq;

    // 预期exp#1 - 第二个被匹配
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_))
        .Times(1)
        .WillOnce(Return(true))
        .InSequence(seq);
    // 此处省略其他预期

    // 预期exp#2 - 第一个被匹配
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_))
        .Times(1)
        .WillOnce(Return(true))
        .InSequence(seq);
    // 此处省略其他预期

    _at_protocol_mock.select_operator(some_var, another_var); // 匹配exp#2
    _at_protocol_mock.select_operator(some_var, another_var); // 匹配exp#1
}

Sequence会严格按照预期绑定的顺序匹配调用,即使签名相同,也会按声明顺序触发。

方法2:利用InSequence作用域调整预期顺序

如果不需要跨作用域的序列控制,可以用InSequence作用域,同时调整预期的声明顺序(因为你需要第一次调用匹配exp#2,所以先声明exp#2):

TEST_F(at_operator_selection_tests, select_operators_selects_operator_with_best_signal)
{
    // arrange
    InSequence s;

    // 先声明exp#2 - 第一个被匹配
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).WillOnce(Return(true));
    // 此处省略其他预期

    // 再声明exp#1 - 第二个被匹配
    EXPECT_CALL(_at_protocol_mock, select_operator(_,_)).WillOnce(Return(true));
    // 此处省略其他预期

    _at_protocol_mock.select_operator(some_var, another_var); // 匹配exp#2
    _at_protocol_mock.select_operator(some_var, another_var); // 匹配exp#1
}

注意:InSequence作用域内的预期会按声明顺序匹配,而GoogleMock默认的逆序匹配规则仅在无序列约束时生效。当有InSequence或Sequence约束时,会优先遵循序列顺序。

关键总结

  • GoogleMock默认对相同签名的预期采用逆序匹配,无序列约束时,最后声明的预期会被优先匹配。
  • InSequence是作用域自动序列,Sequence是手动绑定序列,两者用法不同,不要混淆。
  • 要实现顺序匹配相同调用,要么用Sequence手动绑定,要么用InSequence作用域并调整预期声明顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:12:27