如何在GMock中允许log方法任意穿插于指定有序调用之间?
问题与解决方案
需求
需要校验一组方法(foo、bar、baz)的调用顺序,但这些方法之间可以任意穿插log方法调用,log可被调用任意次数。以下方案不可行:
- 为每个
EXPECT_CALL单独设置InSequence的部分排序:实际测试中有大量EXPECT_CALL,很多位于难以修改的辅助方法中,成本太高。 - 在其他
EXPECT_CALL之间重复添加EXPECT_CALL(mock, log):操作繁琐,不现实。 - 使用全局
InSequence对象后尝试用Sequence覆盖:全局InSequence会作用于所有期望,无法局部覆盖。
解决方案
核心思路是仅将需要保证顺序的方法绑定到同一个序列,让log的期望不受任何序列约束,同时允许其被调用任意次数。具体实现如下:
修改后的测试代码
#include <gtest/gtest.h> #include <gmock/gmock.h> class my_mock { public: MOCK_METHOD(void, foo, ()); MOCK_METHOD(void, bar, ()); MOCK_METHOD(void, baz, ()); MOCK_METHOD(void, log, ()); }; class my_test : public testing::TestWithParam<uint32_t> {}; void test(my_mock& mock, uint32_t mask) { if (mask & 1) mock.log(); mock.foo(); if (mask & 2) mock.log(); mock.bar(); if (mask & 4) mock.log(); mock.baz(); if (mask & 8) mock.log(); } TEST_P(my_test, my_test) { testing::StrictMock<my_mock> mock{}; testing::Sequence ordered_methods{}; // 允许log在任意时机被调用任意次数,不受顺序约束 EXPECT_CALL(mock, log).Times(testing::AnyNumber()); // 强制foo、bar、baz按顺序调用 EXPECT_CALL(mock, foo).Times(1).InSequence(ordered_methods); EXPECT_CALL(mock, bar).Times(1).InSequence(ordered_methods); EXPECT_CALL(mock, baz).Times(1).InSequence(ordered_methods); test(mock, GetParam()); } INSTANTIATE_TEST_SUITE_P( my_test, my_test, testing::Range<uint32_t>(0, 16) );
原理说明
testing::Sequence ordered_methods:创建一个序列对象,仅将foo、bar、baz的期望绑定到该序列,确保它们的调用顺序严格符合声明顺序。EXPECT_CALL(mock, log).Times(testing::AnyNumber()):未绑定到任何序列,因此log可以在foo、bar、baz调用的任意位置出现,次数不限。- 避免使用全局
InSequence对象:全局InSequence会让后续所有EXPECT_CALL默认加入该序列,导致log的调用也被强制约束顺序,不符合需求。
内容的提问来源于stack exchange,提问作者Dominik Kaszewski
相关产品推荐
相关产品推荐

