如何在测试结束后告诉GoogleMock停止检查期望?

Tam*_*lei 6 c++ unit-testing googletest googlemock

我有两个单元测试共享一些状态(不幸的是我不能改变这个,因为重点是测试处理这个状态).

TEST(MySuite, test1)
{
    shared_ptr<MockObject> first(make_shared<MockObject>());
    SubscribeToFooCallsGlobal(first);
    EXPECT_CALL(*first, Foo(_));//.RetiresOnSaturation();
    TriggerFooCalls(); // will call Foo in all subscribed
}

TEST(MySuite, test2)
{
    shared_ptr<MockObject> second(make_shared<MockObject>());
    SubscribeToFooCallsGlobal(second);
    EXPECT_CALL(*second, Foo(_)).Times(1);
    TriggerFooCalls(); // will call Foo in all subscribed
}
Run Code Online (Sandbox Code Playgroud)

如果我单独运行测试,两者都是成功的.如果我在test1,test2的命令中运行它们,我将在test2中收到以下错误:

mytest.cpp(42): error: Mock function called more times than expected - returning directly.
    Function call: Foo(0068F65C)
         Expected: to be called once
           Actual: called twice - over-saturated and active

失败的期望是test1中的期望.电话确实发生了,但我想告诉GoogleMock 完成后不关心test1(事实上​​,我只想在测试运行时检查测试中的期望).

我的印象是RetiresOnSaturation会这样做,但有了它,我得到:

Unexpected mock function call - returning directly.
    Function call: Foo(005AF65C)
Google Mock tried the following 1 expectation, but it didn't match:

mytest.cpp(42): EXPECT_CALL(first, Foo(_))...
         Expected: the expectation is active
           Actual: it is retired
         Expected: to be called once
           Actual: called once - saturated and retired

我不得不承认,让我感到困惑.这是什么意思?我怎么解决这个问题?

Pio*_*ycz 6

您可以阅读Mock的文档,几乎完全描述了您的案例:

强制验证

当它被破坏时,你友好的模拟对象将自动验证对它的所有期望是否已经满足,如果没有,将生成Google Test失败.这很方便,因为它让您不必担心.也就是说,除非你不确定你的模拟对象是否会被破坏.

怎么可能你的模拟对象最终不会被销毁?好吧,它可能是在堆上创建的,并且由您正在测试的代码拥有.假设该代码中存在错误并且它没有正确删除模拟对象 - 当实际存在错误时,您最终可能会通过测试.

所以你不能指望,在测试案例的最后,以某种神奇的方式,期望将被"停用".如上所述 - 模拟析构函数是验证点.

在你的情况下 - 你的SubscribeToFooCallsGlobal()模拟不是局部变量 - 它们是在动态内存中创建的(引用文档中的堆)并保存在测试的代码中,所以当然,在下一次测试中,在一次测试中创建的模拟仍然存在.

简单而恰当的解决方案是在每个TC结束时取消订阅 - 我不知道你是否有UnsubscribeToFooCallsGlobal()- 如果没有 - 创建这样的功能.为了确保它始终被调用 - 使用ScopeGuard模式.

有一个函数可以手动强制执行验证Mock::VerifyAndClearExpectations(&mock_object)- 但只有在您不需要在测试用例的最后一行中进行此验证时才使用它,因为这应该是破坏点.