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
相关产品推荐
相关产品推荐

