在测试中,我使用模拟服务。我想检查服务是否使用其中一个参数的特定属性调用一次。 但是,该方法也被称为多次与其他参数,但我只对上面的一个调用感兴趣。
我的目的是使用参数捕获器验证调用,以检查感兴趣的调用是否仅被调用一次。 但是这会失败,因为该方法被多次调用,之后会检查参数captor。
见下面的例子:
// service method
void serviceMethod(String someString, MyType myType);
// parameter type
class MyType {
private String id;
...
String getID() {
return id;
}
}
// test verification
ArgumentCaptor<MyType> paramCaptor = ArgumentCaptor.forClass(MyType.class);
// fail in verify
Mockito.verify(serviceMock, times(1)).serviceMethod(eq("someConstantValue"), paramCaptor);
assertEquals("123", paramCaptor.getValue().getID());
答案 0 :(得分:3)
我用hamcrest Matcher
解决了这个问题。匹配器在验证方法调用时检查参数值,而参数捕获器仅读取参数以供以后评估。
在这种情况下,所有其他具有未指定值的调用都将被过滤掉。
static Matcher<MyType> typeIdIs(final String id) {
return new ArgumentMatcher<MyType>() {
@Override
public boolean matches(Object argument) {
return id.equals(((MyType)argument).getID());
}
};
}
Mockito.verify(serviceMock, times(1)).serviceMethod(eq("someConstantValue"), argThat(typeIdIs("123")));
答案 1 :(得分:2)
您可以使用atLeastOnce()
和getAllValues()
:
MyService service = mock( MyService.class );
ArgumentCaptor<MyType> captor = ArgumentCaptor.forClass( MyType.class );
service.serviceMethod( "foo", new MyType( "123" ) );
service.serviceMethod( "bar", new MyType( "312" ) );
service.serviceMethod( "baz", new MyType( "231" ) );
verify( service, atLeastOnce() ).serviceMethod( anyString(), captor.capture() );
List<String> ids = captor.getAllValues().stream().map( MyType::getId ).collect( Collectors.toList() );
assertThat( ids ).contains( "123" );
请注意,我正在使用static imports以及AssertJ断言和匹配器,但您应该能够轻松地将此映射到JUnit或其他内容。
编辑:如果您想确保只有一次出现"123"
,可以使用Collections#frequency( Collection, Object )
:
assertThat( Collections.frequency( ids, "123" ) ).isEqualTo( 1 );
甚至更好:看看AssertJ conditions。
答案 2 :(得分:1)
如果您在Java 8中使用Mockito 2,那么可以采用一种巧妙的方法。见http://static.javadoc.io/org.mockito/mockito-core/2.2.9/org/mockito/Mockito.html#36
该示例将重构为:
// service method
void serviceMethod(String someString, MyType myType);
// parameter type
class MyType {
private String id;
...
String getID() {
return id;
}
}
// using a Java 8 lambda to test the ID within a custom ArgumentMatcher
// passed to argThat
// Note: you don't need to say "times(1)" as this assumes 1 time
// times(1) in the argument captor version would also confuse things
// if you had other calls and you
// were just checking for whether a call like THIS had happens
Mockito.verify(serviceMock).serviceMethod(eq("someConstantValue"),
argThat(input -> input.getID().equals("123")));
lambda使它更干净,但你需要Java 8和Mockito 2。
答案 3 :(得分:-1)
编辑:
我不知道如何完全按照你的要求去做。
我喜欢@ beatngu13的答案。
但是,另一个选项可能是将atLeastOnce()与有序验证结合使用:
InOrder inOrder = inOrder(serviceMock);
inOrder.verify(serviceMock, atLeastOnce()).serviceMethod(eq("someConstantValue"), paramCaptor);
inOrder.verify(serviceMock).serviceMethod(eq("someConstantValue"), fakeParamOne);
inOrder.verify(serviceMock).serviceMethod(eq("someConstantValue"), fakeParamTwo);
assertEquals("123", paramCaptor.getValue().getID());
您可以在其中创建一个伪造的对象,该对象看起来类似于您对该服务的其他调用的参数。