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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:20:00