问题描述
如果我在同一个 TEST_F
中的同一个模拟对象上两次调用 EXPECT_CALL
...会发生什么?
If I call EXPECT_CALL
twice on the same mock object in the same TEST_F
. . . what happens?
是否将期望附加到模拟对象上,还是第二次调用消除了第一次调用的影响?
Are the expectations appended to the mock object or does the second call erase the effects of the first call?
我发现了之后子句似乎暗示允许多次调用同一个模拟+ EXPECT_CALL.
I found The After Clause which appears to imply that multiple calls to same mock + EXPECT_CALL are allowed.
推荐答案
是的,您可以在同一个模拟对象上多次调用 EXPECT_CALL
.只要您确保在实际使用模拟方法之前调用了所有 EXPECT_CALL
.否则你的测试将依赖于未定义的行为.来自 ForDummies:
Yes, you can call EXPECT_CALL
on the same mock object multiple times. As long as you assure that all EXPECT_CALL
were called before the mocked methods were actually used. Otherwise your test will rely on undefined behavior. From ForDummies:
重要说明:gMock 要求在调用模拟函数之前设置期望值,否则行为未定义.特别是,您不能将 EXPECT_CALL() 和对模拟函数的调用交织在一起.
如何处理多个呼叫?文档非常简单.来自 ForDummies:
How multiple calls will be handled? The documentation is really straightforward. From ForDummies:
默认情况下,当调用一个模拟方法时,Google Mock 会搜索以相反的顺序定义期望,并在出现时停止找到与参数匹配的主动期望(你可以认为将其视为新规则覆盖旧规则.").
让我们通过一些示例来考虑这对 gMock 用户意味着什么.我假设我们有一个带有以下标题的文件:
Let's consider what this means for the gMock user, by checking some examples. I assume that we have a file with following header:
#include <gmock/gmock.h>
using namespace ::testing;
struct SomeMock
{
MOCK_CONST_METHOD1(foo, void(int));
};
多次调用EXPECT_CALL
的通过测试的最简单示例:
The simplest example of passing test that calls EXPECT_CALL
multiple times:
TEST(Examples, DifferentArgumentsGoingToBeOk)
{
SomeMock mock;
EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
EXPECT_CALL(mock, foo(5)).Times(1); // exp#2
mock.foo(4); // call#1
mock.foo(5); // call#2
}
测试直观:
call#1
与exp#2
不匹配,所以exp#1
被尝试并匹配.call#2
与exp#2
匹配.
call#1
does not match withexp#2
soexp#1
is tried and matches.call#2
matches withexp#2
.
两个调用只匹配一次,因此它们被认为是满意的并且测试通过.
Both calls matched exactly once, thus they are considered satisfied and the test passes.
当多个 EXPECT_CALL
能够匹配调用时,棘手的部分就开始了.让我们考虑以下示例:
The tricky part starts when multiple EXPECT_CALL
are able to match the call. Let's consider the following example:
TEST(Examples, TheSameArgumentsGoingToFail) // Test fails!
{
SomeMock mock;
EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1); //exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
call#1
匹配exp#2
.gMock 在第一个匹配的期望值处停止,它根本不会检查exp#1
.call#2
匹配exp#2
.exp#1
再次没有机会被匹配.- The
call#1
matches theexp#2
. gMock stops at first matched expectation, it won't check theexp#1
at all. - The
call#2
matches theexp#2
. Again theexp#1
does not have chance to be matched.
结果测试失败,因为 exp#2
被匹配两次而不是一次,并且 exp#1
根本不匹配.测试输出中打印的所有内容:
As a result the test fails as the exp#2
gets matched twice instead of once and exp#1
is not matched at all. All that is printed in the test output:
/tmp/so/main.cpp:26: Failure // exp#2
Mock function called more times than expected - returning directly.
Function call: foo(4)
Expected: to be called once
Actual: called twice - over-saturated and active
/tmp/so/main.cpp:25: Failure // exp#1
Actual function call count doesn't match EXPECT_CALL(mock, foo(4))...
Expected: to be called once
Actual: never called - unsatisfied and active
此外,重要的是,添加新的预期不会禁用或删除旧的.他们仍然可以通过您的测试!
Also, it is important, that adding new expectancy won't disable or remove old ones. They are still able to fail your test!
TEST(Examples, NewExpectCallDoesNotEraseThePreviousOne) // Test fails!
{
SomeMock mock;
EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
EXPECT_CALL(mock, foo(4)).Times(2); // exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
call#1
和 call#2
都匹配 exp#2
.结果 exp#2
得到满足,但测试将失败,因为 exp#1
匹配的次数不够多.
Both call#1
and call#2
matches the exp#2
. As a result the exp#2
is satisfied, but the test will fail as exp#1
was not matched enough times.
如果出于某种原因,您需要编写像 TheSameArgumentsGoingToFail
这样的测试,您可以使用多种技术来防止 exp#2
再次匹配.请参阅文档 InSequence 用法,RetiresOnSaturation:
If for some reason, you need to write a test like TheSameArgumentsGoingToFail
, you can use a number of techniques to prevent exp#2
from matching second time. Please refer to the documentation InSequence usage, RetiresOnSaturation:
TEST(Examples, InSequenceExample)
{
SomeMock mock;
Sequence seq;
EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
TEST(Examples, InSequenceExampleSecondApproach)
{
SomeMock mock;
InSequence seq;
EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1); //exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
TEST(Examples, RetiresOnSaturationExample)
{
SomeMock mock;
EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).RetiresOnSaturation(); //exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
TEST(Examples, AfterExample)
{
SomeMock mock;
auto& exp1 = EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).After(exp1); //exp#2
mock.foo(4); // call#1
mock.foo(4); // call#2
}
这篇关于谷歌模拟 - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!