Java 测试模拟对象的良好实践

Java 测试模拟对象的良好实践,java,testing,mocking,coding-style,Java,Testing,Mocking,Coding Style,很好的做法是广泛匹配模拟对象,但精确地验证它们。 例如: 使用此选项: when(myMock.has(any())).thenReturn(myValue); 而不是: when(myMock.has(eq("blah")).thenReturn(myValue); 以及: var result = myMethod(); assertThat(result, is(myValue)); 因为它确保总是返回myValue,而不管是否有方法输入 这条规则有很好的解释,但

很好的做法是广泛匹配模拟对象,但精确地验证它们。 例如:

使用此选项:

when(myMock.has(any())).thenReturn(myValue);
而不是:

when(myMock.has(eq("blah")).thenReturn(myValue);
以及:

var result = myMethod();
assertThat(result, is(myValue));
因为它确保总是返回
myValue
,而不管
是否有
方法输入

这条规则有很好的解释,但我找不到。 大致如下:
广泛匹配并精确验证


如果你能告诉我规则的名称或一些参考信息,那就太好了。

解释很简单:这会让你的生活更轻松。

想象一下,调用方不会用“废话”调用您的方法。在这种情况下,您依赖于模拟框架将返回什么,很可能是null、zero或false。然后,您的测试将运行到不同的方向,甚至会因NullpointerException而失败。对于其他开发人员来说,很难理解这里出了什么问题

如果您广泛匹配,您的测试将按预期继续,但是您应该在之后进行验证,以使测试以明确的原因失败。开发人员往往会忽略验证步骤,这常常会使测试变得无用。 通常没有理由匹配精确的参数值,除非您希望您的模拟对两个值采取不同的操作

大多数框架提供方法调用验证的方法,例如Mockito:

@Mock
private Repository repository;

@Test
private void testReadData() {
    Mockito.when(repository.findById(any())).thenReturn(yourEntity);
    
    // run your test
    
    Mockito.verify(repository).findById("foo");
}

实际上这两种方法都是正确的。一切都取决于您想要测试的测试用例。