Java Mockito在改变行为时调用mocked方法一次
我遇到了一个非常奇怪的行为,以防在测试期间更改模拟行为。我模拟了一个非常简单的界面:Java Mockito在改变行为时调用mocked方法一次,java,mocking,mockito,junit5,Java,Mocking,Mockito,Junit5,我遇到了一个非常奇怪的行为,以防在测试期间更改模拟行为。我模拟了一个非常简单的界面: interface Bar { String string(String str); } @Mock private Bar bar; 然后我调用它并使用AtomicInteger计算调用次数,这是这个最小工作示例的一个副作用 @Test public void test() { AtomicInteger atomicInteger = new AtomicInteger(0);
interface Bar {
String string(String str);
}
@Mock
private Bar bar;
然后我调用它并使用AtomicInteger
计算调用次数,这是这个最小工作示例的一个副作用
@Test
public void test() {
AtomicInteger atomicInteger = new AtomicInteger(0);
// Mock with the increment
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> {
log.info("MOCK - waiting (1): {}", invocation.getArguments()[0]);
atomicInteger.incrementAndGet();
log.info("MOCK - returning (1)");
return "BAR_1";
});
// Invocation of the increment
log.info("Result (1): " + bar.string("FOO_1"));
// Passes
Assertions.assertEquals(1, atomicInteger.get());
}
只要使用bar.string(“FOO_1”)
一次调用该方法,测试就会通过。只要我在执行后添加mockbar
的新行为,以不增加AtomicInteger
,就会再次调用不应调用的原始mock:
@Test
public void test() {
AtomicInteger atomicInteger = new AtomicInteger(0);
// Mock with the increment
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> {
log.info("MOCK - waiting (1): {}", invocation.getArguments()[0]);
atomicInteger.incrementAndGet();
log.info("MOCK - returning (1)");
return "BAR_1";
});
// Invocation with increment
log.info("Result (1): " + bar.string("FOO_1"));
/* NEW CODE BLOCK STARTS */
// Mock without the increment
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> {
log.info("MOCK - returning (2): {}", invocation.getArguments()[0]);
return "BAR_2";
});
// Invocation without the increment
// The previous lines really changed the mock, but it was called one more times
log.info("Result (2): " + bar.string("FOO_2"));
/* NEW CODE BLOCK ENDS */
// Fails, it is 2
Assertions.assertEquals(1, atomicInteger.get());
}
令人惊讶的是,日志显示在第4行调用mock方法时没有参数
当我在同一测试N
-次中包含更多这段代码时,行为不会改变。测试总是失败,期望增量为2
,而不是1
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> {
log.info("MOCK - returning (N): {}", invocation.getArguments()[0]);
return "BAR_N";
});
log.info("Result (N): " + bar.string("FOO_N"));
是什么使得Mockito在其行为在测试1+次期间发生更改后,只调用一次带有模拟参数的模拟方法?在remocking操作中调用bar.string(Mockito.anyString())
仍然相当于调用bar.string(string)
,它在前面被模拟以增加原子整数
log.info("Result (1): " + bar.string("FOO_1")); // Increases to 1
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> { // Increases to 2
重新填充后,随着新模拟生效,该数字不再增加。您应该使用,以避免编写脆弱或复杂的测试代码。您实际上不是在手动编写调用计数和参数检查,是吗?它们有现成的机制。@Kayaman:这是一个无关紧要的问题。我用一个最小的工作示例来演示Mockito在副作用方面的奇怪的behvaior。考虑<代码> AtomicInteger:将增量和获取< /代码>作为副作用方法。您正在移除一种方法来做一些不必要的事情。我需要验证你是否意识到你在做一些奇怪的事情,所以你也不应该对你得到的奇怪结果感到惊讶。最重要的是重置或重建您的mock,这一结果的原因是在内部实现中。我正在重新检查一个方法,以避免产生副作用(因此没有增量),并演示如何调用原始mock方法(使用增量),尽管在调用一次时只应调用一次。第二次调用发生在重新标记的方法上,没有副作用(没有增量)。实际上,最初的方法仍然以某种方式被再次调用。我知道我在做什么,这就是为什么我对它给我的结果感到惊讶。您如何解释第二个日志中的第四行?当您尝试重新修改方法时,为什么您认为
bar.string(“FOO_1”)
会增加AtomicInteger
和bar.string(Mockito.anyString())
?它们都调用了mock方法,从而增加了数量,这就是为什么您不应该尝试重新修改该方法的原因!这是一个方法调用,唯一肯定不会产生副作用的地方是一个空的mock,以前被mock的方法不是空的。我已经用Mockito.when(..).then(..)then(..)
链解决了这个问题。
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> {
log.info("MOCK - returning (N): {}", invocation.getArguments()[0]);
return "BAR_N";
});
log.info("Result (N): " + bar.string("FOO_N"));
log.info("Result (1): " + bar.string("FOO_1")); // Increases to 1
Mockito.when(bar.string(Mockito.anyString())).then(invocation -> { // Increases to 2