我试图了解EXPECT_CALL的工作原理,并且遇到了奇怪的行为(我认为很奇怪)。假设我的代码做到了这一点(假设有一个模拟并且f(int)是它的方法,还假设SomeNiceMock是NiceMock):
void SomeMock::f(int) { ... }
NiceMock<SomeMock> someNiceMock;
void runCycle(int n) { someNiceMock.f(n); }
现在,如果在测试中,我将执行以下操作
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);
::testing::Mock::VerifyAndClearExpectations(&mock);
我得到一个错误,假设f(int)被调用为2,但被调用为1。
Expected: to be called at least once
Actual: never called - unsatisfied and active
如果我这样做的话:
runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);
::testing::Mock::VerifyAndClearExpectations(&mock);
一切正常。
我可以忍受这种行为,只是我不了解其背后的原因。 someNiceMock是一个NiceMock,因此只要实际使用预期参数调用f(int),它就不应抱怨使用其他预期参数调用f(int)。第二次调用runCycle(2)确实调用了f(2)。那么,为什么不仅仅忽略调用f(1)并且测试失败呢?是这样的,如果我为一个NiceMock甚至指定一个EXPECT_CALL如果此调用将使用不同的参数(但是稍后将使用适当的参数进行另一个调用),则测试将失败?认为这是一个NiceMock并实际上在两种情况下都发生了对f(2)的调用,这不是直觉吗?
编辑:那我该如何测试这种行为?假设我有一些数字生成器,我想测试一下,当它被调用10次时它至少返回3次5(而且我不在乎其他结果。我希望这样编码(对不起,如果我搞砸了语法,我不太擅长Google模拟):
struct INumberGeneratorSink {
virtual void consumeNumber(int number) = 0;
};
struct NumberGeneratorSink : public INumberGeneratorSink {
void consumeNumber(int number) override { ... }
};
struct NumberGeneratorSinkMock : public INumberGeneratorSink {
MOCK_METHOD1(consumeNumber, void(int number));
};
void numberGeneratorFunction(INumberGeneratorSink &sink)
{
for (int i = 0; i < 10; i++)
{
sink.consumeNumber(getNumberFromSomewhere());
}
}
NumberGeneratorSinkMock sinkMock;
NiceMock<NumberGeneratorSinkMock> niceSinkMock;
EXPECT_CALL(niceSinkMock, consumeNumber(5)).Times(AtLeast(3));
numberGeneratorFunction(niceSinkMock);
我该如何编码这样的东西?如果存在一些语法错误,请纠正我,但是我的问题更像是-如果我只在乎将该消耗数字以值5调用3次,而我不在乎其余如何编码呢?我必须写类似的东西吗?
// not sure about syntax for Any(),
// maybe it doesn't exist and has to be AtLeast(1)
EXPECT_CALL(niceSinkMock, consumeNumber(_)).Times(Any());
EXPECT_CALL(niceSinkMock, consumeNumber(5)).Times(AtLeast(3));
那行得通吗?首先EXPECT_CALL是否会完全匹配所有内容,并且即使从不使用5作为参数调用invokeNumber,测试也会通过吗?
答案 0 :(得分:2)
我完全同意,gmock可能会对期望感到困惑。 ;-)
1)为什么以下操作失败?
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);
如果模拟方法没有EXPECT_CALL而是被调用,则Google Mock将打印警告。要取消显示此警告,可以使用NiceMock。但是,如果存在EXPECT_CALL,它将并且应该失败。
2)为什么以下通过?
runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);
简单的答案:必须先编写EXPECT_CALL。但是这种编写测试的方法不应该是通常的方法。
3)处理多个期望的解决方案
”“默认情况下,当调用模拟方法时,Google Mock将按照定义的相反顺序搜索期望,并在出现期望时停止 找到与参数匹配的积极期望”
您上次被截断的代码几乎是正确的。 Times(Any())的正确实现是忽略它。
EXPECT_CALL(someNiceMock, f(_));
EXPECT_CALL(someNiceMock, f(2)).Times(1);
runCycle(1);
runCycle(2);
还请注意,您的模拟“ SomeMock”需要“模拟”方法。 例如:
class SomeMock {
public:
MOCK_CONST_METHOD1(f, void(int i));
};