用ArgumentCaptor验证模拟服务调用失败



在一个测试中,我使用了一个模拟服务。我想检查是否使用其中一个参数的特定属性调用了一次服务。然而,该方法也可以用其他参数调用多次,但我只对上面的一次调用感兴趣。

我的目的是用参数捕获器验证调用,以检查感兴趣的调用是否只调用一次。然而,这将失败,因为该方法将被多次调用,并且参数捕获器将在之后进行检查。

请看下面的例子:

// 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());

我用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")));

您可以使用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" );

请注意,我使用静态导入以及AssertJ断言和匹配器,但您应该能够轻松地将其映射到JUnit或其他东西。

EDIT:如果您想确保只出现一次"123",您可以使用Collections#frequency( Collection, Object ):

assertThat( Collections.frequency( ids, "123" ) ).isEqualTo( 1 );

或者更好:看一下AssertJ条件

如果您在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。

EDIT:

我不知道怎么做你所要求的。

我喜欢@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());

,其中创建了一个fakeParam对象,该对象看起来类似于其他服务调用的参数

相关内容

  • 没有找到相关文章

最新更新