如何在首次出现未预期的gmock调用时终止gtest测试
问题:是否存在与ASSERT_*等效的EXPECT_CALL机制,可在首次不匹配调用时终止测试?
在使用gtest+gmock测试硬件寄存器编程序列时,所有EXPECT_CALL均基于StrictMock和InSequence。一旦出现调用缺失或错误,后续调用大概率会因序列错位产生大量冗余错误信息,难以定位根本故障。
示例代码
#include <gmock/gmock.h> #include <gtest/gtest.h> #include <cstdint> void hw_register_write(uint32_t, uint32_t) {} class hw_register_access { public: virtual void write(uint32_t address, uint32_t value) = 0; }; class hw_registers : public hw_register_access { public: void write(uint32_t address, uint32_t value) override { return hw_register_write(address, value); } }; class mock_registers : public hw_register_access { public: MOCK_METHOD(void, write, (uint32_t address, uint32_t value), (override)); }; void program_foo(hw_register_access& reg) { reg.write(0x10, 0x123); reg.write(0x10, 0x456); // 此处存在错误,希望测试立即终止 for (size_t i = 0; i < 10; i++) { reg.write(0x20, 0x789); // 不希望此处产生冗余错误信息 } } TEST(programming_sequence_test, program_foo) { testing::StrictMock<mock_registers> mock{}; testing::InSequence seq{}; EXPECT_CALL(mock, write(0x10, 0x123)); EXPECT_CALL(mock, write(0x11, 0x456)); EXPECT_CALL(mock, write(0x20, 0x789)).Times(10); program_foo(mock); }
现有问题
当出现不匹配调用时,测试会继续执行后续代码,生成大量冗余错误(如示例中会产生300多行输出),掩盖了根本问题:
Unexpected mock function call - returning directly. Function call: write(16, 1110) ... Expected arg #0: is equal to 17 Actual: 16
解决方案
gmock没有直接提供ASSERT_CALL宏,但可以通过以下两种方式实现首次失败即终止测试:
方法1:启用失败时抛出异常
通过设置testing::GTEST_FLAG(throw_on_failure)为true,让gtest/gmock在检测到第一个失败时抛出异常,立即终止测试执行,避免后续冗余错误。
修改后的测试代码:
TEST(programming_sequence_test, program_foo) { // 开启失败即抛出异常 testing::GTEST_FLAG(throw_on_failure) = true; testing::StrictMock<mock_registers> mock{}; testing::InSequence seq{}; EXPECT_CALL(mock, write(0x10, 0x123)); EXPECT_CALL(mock, write(0x11, 0x456)); EXPECT_CALL(mock, write(0x20, 0x789)).Times(10); program_foo(mock); // 可选:恢复全局设置,避免影响其他测试用例 testing::GTEST_FLAG(throw_on_failure) = false; }
方法2:自定义测试监听器(进阶)
如果需要更精细的控制,可以自定义gtest监听器,在检测到第一个失败时终止测试执行。这种方式适合全局统一配置的场景:
class FailFastListener : public testing::EmptyTestEventListener { public: void OnTestPartResult(const testing::TestPartResult& result) override { if (result.failed()) { // 终止所有测试执行 testing::UnitTest::GetInstance()->Abort(); } } }; TEST(programming_sequence_test, program_foo) { static bool listener_added = false; if (!listener_added) { testing::UnitTest::GetInstance()->listeners().Append(new FailFastListener()); listener_added = true; } testing::StrictMock<mock_registers> mock{}; testing::InSequence seq{}; EXPECT_CALL(mock, write(0x10, 0x123)); EXPECT_CALL(mock, write(0x11, 0x456)); EXPECT_CALL(mock, write(0x20, 0x789)).Times(10); program_foo(mock); }
总结
推荐优先使用方法1,实现简单且能快速解决冗余错误问题。如果需要全局生效的失败终止策略,可以选择方法2。
内容的提问来源于stack exchange,提问作者Dominik Kaszewski
相关产品推荐
相关产品推荐

