GMock技术问询:如何实现任意顺序块内的调用序列约束
如何用GMock实现支持调用对顺序调整的成对约束测试?
业务代码说明
给定接口定义:
class Interface { public: virtual ~Interface = default; virtual void open(int id) = 0; virtual void close() = 0; protected: // 默认其他特殊成员 };
核心规则:
close()只能在open()之后调用- 下一次调用
open()前必须先调用close()(同一时间只能有一个打开的ID) open()的ID不可重复
合法实现要求每个ID的open()/close()成对调用,且成对的顺序可调整(比如先处理ID2的成对,再处理ID1的);以下错误实现因违反规则需被识别:
void actWrong(Interface & interface) { interface.open(1); interface.open(2); interface.open(3); interface.close(); interface.close(); interface.close(); }
测试需求
- 调整
open()/close()调用对的顺序时,测试仍通过 - 成对规则被破坏(连续调用
open、连续调用close、重复ID等)时,测试失败
现有尝试的问题
- 使用
InSequence:能满足成对约束,但无法支持调用对的顺序调整 - 使用
Sequence:支持顺序调整,但无法识别成对规则的破坏 - 状态跟踪方式:需重复实现业务逻辑,扩展性差
解决方案
借助GMock的InSequence全局序列约束,结合Unique参数匹配器,可以同时满足顺序调整支持和规则校验的需求:
1. 定义Mock类
class MockInterface : public Interface { public: MOCK_METHOD(void, open, (int id), (override)); MOCK_METHOD(void, close, (), (override)); };
2. 编写测试用例
合法调用场景(支持顺序调整)
TEST(InterfaceTest, ValidCallPairsWithAdjustedOrder) { MockInterface mock; Sequence global_seq; // 全局序列强制调用顺序为:open -> close -> open -> close(可扩展到更多成对) EXPECT_CALL(mock, open(_)) .InSequence(global_seq) .Times(2) .With(Args<0>(Unique())); // 确保ID唯一 EXPECT_CALL(mock, close()) .InSequence(global_seq) .Times(2); // 测试合法顺序:先处理ID2的成对,再处理ID1的 mock.open(2); mock.close(); mock.open(1); mock.close(); }
非法调用场景(连续open)
TEST(InterfaceTest, InvalidConsecutiveOpens) { MockInterface mock; Sequence global_seq; EXPECT_CALL(mock, open(_)) .InSequence(global_seq) .Times(2) .With(Args<0>(Unique())); EXPECT_CALL(mock, close()) .InSequence(global_seq) .Times(2); // 执行错误调用:连续open两个ID,违反全局序列约束 mock.open(1); mock.open(2); // 此处触发测试失败 }
非法调用场景(重复ID)
TEST(InterfaceTest, InvalidDuplicateID) { MockInterface mock; Sequence global_seq; EXPECT_CALL(mock, open(_)) .InSequence(global_seq) .Times(2) .With(Args<0>(Unique())); EXPECT_CALL(mock, close()) .InSequence(global_seq) .Times(2); // 执行错误调用:重复使用ID1 mock.open(1); mock.close(); mock.open(1); // 此处触发测试失败 }
方案说明
InSequence(global_seq):强制全局调用顺序必须是open与close交替,直接约束了“下一次open前必须调用close”以及“close只能在open之后调用”的规则,同时允许调整成对的顺序(只要整体是交替的)。Args<0>(Unique()):利用GMock原生匹配器确保所有open的ID不重复,无需手动维护状态集合。Times(n):指定成对的数量,可根据测试场景灵活调整(比如测试3个成对调用时,将Times改为3即可)。
这种方案完全基于GMock原生功能,避免了重复实现业务逻辑,同时满足所有测试需求。
内容的提问来源于stack exchange,提问作者Brandlingo
相关产品推荐
相关产品推荐

