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

Java 使用ArgumentCaptor验证模拟服务调用失败,java,unit-testing,mockito,Java,Unit Testing,Mockito,在测试中,我使用模拟服务。我想检查服务是否使用其中一个参数的特定属性调用过一次。 然而,这个方法也被称为multiple times和其他参数,但我只对上面的一个调用感兴趣 我的意图是使用参数捕获器验证调用,以检查感兴趣的调用是否只被调用一次。 但是,这失败了,因为该方法被多次调用,并且随后检查参数captor 见下例: // service method void serviceMethod(String someString, MyType myType); // parameter ty

在测试中,我使用模拟服务。我想检查服务是否使用其中一个参数的特定属性调用过一次。 然而,这个方法也被称为multiple times和其他参数,但我只对上面的一个调用感兴趣

我的意图是使用参数捕获器验证调用,以检查感兴趣的调用是否只被调用一次。 但是,这失败了,因为该方法被多次调用,并且随后检查参数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());
//服务方法
void serviceMethod(字符串someString,MyType MyType);
//参数类型
类MyType{
私有字符串id;
...
字符串getID(){
返回id;
}
}
//试验验证
ArgumentCaptor paramCaptor=ArgumentCaptor.forClass(MyType.class);
//验证失败
Mockito.verify(serviceMock,times(1)).serviceMethod(等式(“someConstantValue”),paramCaptor);
assertEquals(“123”,paramCaptor.getValue().getID());
编辑:

我不知道有什么方法可以完全满足你的要求

我喜欢@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对象,该对象与服务的其他调用的参数类似。

编辑:

我不知道有什么方法可以完全满足你的要求

我喜欢@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对象,该对象与服务的其他调用的参数类似。

您可以使用
atLeastOnce()
getAllValues()
的组合来实现这一点:


或者更好:看看AssertJ。

您可以使用
atLeastOnce()
getAllValues()
的组合来实现这一点:


或者更好:看看AssertJ。

我用hamcrest
匹配器解决了这个问题。匹配器在验证方法调用时检查参数值,而参数捕获器仅读取参数以供以后评估。
在这种情况下,具有未指定值的所有其他调用都会被过滤掉

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")));
静态匹配器类型id(最终字符串id){
返回新的ArgumentMatcher(){
@凌驾
公共布尔匹配(对象参数){
返回id.equals(((MyType)参数).getID());
}
};
}
Mockito.verify(serviceMock,times(1)).serviceMethod(eq(“someConstantValue”)、argThat(typeIdIs(“123”));

我用hamcrest
匹配器解决了这个问题。匹配器在验证方法调用时检查参数值,而参数捕获器仅读取参数以供以后评估。
在这种情况下,具有未指定值的所有其他调用都会被过滤掉

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")));
静态匹配器类型id(最终字符串id){
返回新的ArgumentMatcher(){
@凌驾
公共布尔匹配(对象参数){
返回id.equals(((MyType)参数).getID());
}
};
}
Mockito.verify(serviceMock,times(1)).serviceMethod(eq(“someConstantValue”)、argThat(typeIdIs(“123”));

如果您将Mockito 2与Java 8一起使用,有一种简洁的方法可以做到这一点。看

该示例将重构为:

// 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。

如果您将Mockito 2与Java 8一起使用,有一种简洁的方法可以做到这一点。看

该示例将重构为:

// 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。

我想验证使用指定参数集只调用了一次服务。我想验证使用指定参数集只调用了一次服务。感谢您的支持。从未想过收集所有值以备以后检查。我用汉克雷斯特匹配器解决了这个问题。@Stefan不客气。添加了另一种方法以确保ID只出现一次。感谢您的支持。从未想过收集所有值以备以后检查。我用汉克雷斯特匹配器解决了这个问题。@Stefan不客气。添加了另一种方法来确保ID只出现一次。这是一种很好的方法。一般来说,论点捕获者是一种反模式。您应该能够通过verify使用参数解决这个问题。这是一个很好的方法。一般来说,论点捕获者是一种反模式。您应该能够通过验证的参数来解决这个问题。