EXPECT_CALL(mock, f(N)) vs f(K) 后跟 f(N)
EXPECT_CALL(mock, f(N)) vs f(K) followed by f(N)
我试图了解 EXPECT_CALLs 的工作原理,但我遇到了一种奇怪的行为(在我看来很奇怪)。假设我的代码执行此操作(假设有一个模拟并且 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 次时 returns 5 至少 3 次(我不关心其他结果。我希望像这样编码(对不起,如果我弄乱了语法,我不太擅长 google mock):
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);
我该如何编写这样的代码?如果有语法错误请纠正我,但我的问题更像是 - 如果我只关心 consumeNumber 被调用 3 次且值为 5 而我不关心其余的我该如何编码?我必须写这样的东西吗:
// 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 作为参数调用 consumeNumber 吗?
我完全同意,gmock 可能会混淆预期。 ;-)
1) 为什么下面会失败?
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);
如果 mock 方法没有 EXPECT_CALL 但被调用,Google Mock 将打印警告。要抑制此警告,您可以使用 NiceMock。但是,如果 EXPECT_CALL 存在,它将并且应该失败。
2) 为什么下面会通过?
runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);
简单的回答:EXPECT_CALL必须先写。但是这种写测试的方式应该不是通常的方式。
3) 处理多重期望的解决方案
"By default, when a mock method is invoked, Google Mock will search the expectations in the reverse order they are defined, and stop when
an active expectation that matches the arguments is found"
你最后截取的代码几乎是正确的。 Times(Any()) 的正确实现是省略它。
EXPECT_CALL(someNiceMock, f(_));
EXPECT_CALL(someNiceMock, f(2)).Times(1);
runCycle(1);
runCycle(2);
另请注意,您的 Mock "SomeMock" 需要一个 "mocked" 方法。
例如:
class SomeMock {
public:
MOCK_CONST_METHOD1(f, void(int i));
};
我试图了解 EXPECT_CALLs 的工作原理,但我遇到了一种奇怪的行为(在我看来很奇怪)。假设我的代码执行此操作(假设有一个模拟并且 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 次时 returns 5 至少 3 次(我不关心其他结果。我希望像这样编码(对不起,如果我弄乱了语法,我不太擅长 google mock):
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);
我该如何编写这样的代码?如果有语法错误请纠正我,但我的问题更像是 - 如果我只关心 consumeNumber 被调用 3 次且值为 5 而我不关心其余的我该如何编码?我必须写这样的东西吗:
// 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 作为参数调用 consumeNumber 吗?
我完全同意,gmock 可能会混淆预期。 ;-)
1) 为什么下面会失败?
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);
如果 mock 方法没有 EXPECT_CALL 但被调用,Google Mock 将打印警告。要抑制此警告,您可以使用 NiceMock。但是,如果 EXPECT_CALL 存在,它将并且应该失败。
2) 为什么下面会通过?
runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);
简单的回答:EXPECT_CALL必须先写。但是这种写测试的方式应该不是通常的方式。
3) 处理多重期望的解决方案
"By default, when a mock method is invoked, Google Mock will search the expectations in the reverse order they are defined, and stop when an active expectation that matches the arguments is found"
你最后截取的代码几乎是正确的。 Times(Any()) 的正确实现是省略它。
EXPECT_CALL(someNiceMock, f(_));
EXPECT_CALL(someNiceMock, f(2)).Times(1);
runCycle(1);
runCycle(2);
另请注意,您的 Mock "SomeMock" 需要一个 "mocked" 方法。 例如:
class SomeMock {
public:
MOCK_CONST_METHOD1(f, void(int i));
};