Java Mockito模拟调用两次的方法调用

Java Mockito模拟调用两次的方法调用,java,unit-testing,junit,mockito,springmockito,Java,Unit Testing,Junit,Mockito,Springmockito,我试图用mockito来模拟一个方法。然而,我正在注入mock的类在发送相同类型的两个不同对象时两次调用该方法,但取决于对象中的值来确定该方法的输出 举个例子,如果我想嘲笑 public ArrayList<example> attemptToMock(testObject testing) public ArrayList attemptomock(测试对象测试) 让sat类型testObject包含一个字符串值 因此,如果testObject中的字符串值为“OK”,则atte

我试图用mockito来模拟一个方法。然而,我正在注入mock的类在发送相同类型的两个不同对象时两次调用该方法,但取决于对象中的值来确定该方法的输出

举个例子,如果我想嘲笑

public ArrayList<example> attemptToMock(testObject testing)
public ArrayList attemptomock(测试对象测试)
让sat类型
testObject
包含一个字符串值

因此,如果testObject中的字符串值为“OK”,则
attemptomock
应在其中输出两个对象的数组。如果
testObject
字符串值为“否”,则发出的数组列表只有一个对象


如何编写一个测试来处理一个调用,这样一个类就可以在同一个方法中调用
attemptomock
两次,并且可以根据
testObject
中的值模拟它的输出。我可以模拟它来发送不同的数组。

您可以访问传递到模拟方法调用中的参数,并使用应答接口相应地改变返回值。请参见,和的答案

基本上,这里发生的唯一奇怪/不明显的事情是,您必须将参数向下转换为您期望的类型。因此,在您的例子中,如果您正在模拟一个采用单个“TestObject”参数的方法,那么您必须在“answer”实现中执行类似的操作:

Object[] args = invocation.getArguments();
TestObject testObj = (TestObject) args[0];
if ("OK".equals(testObj.value)) {
  return new ArrayList(value1, value2);
} else if ("NO".equals(testObj.value)) {
  return new ArrayList(singleObject);
}
有几个选择:

  • 在您的对象(TestObject)上。只有当对象上的所有值都是可预测的,并且可能比其他解决方案更费工时,这才是可行的,但如果您仍然需要编写
    equals
    hashCode
    (例如,对于映射和设置行为),这是一个合理的解决方案

    // Mockito compares with objects' equals(Object) methods by default.
    when(collaborator.attemptToMock(object1)).thenReturn(array1);
    when(collaborator.attemptToMock(object2)).thenReturn(array2);
    
  • 编写一个数组,并使用它来匹配数组。对于特定的情况,这可以作为
    equals
    的紧凑模拟,如果您需要在许多测试中基于相同的值更改行为,那么它尤其方便

    public class IsATestObjectWithValue extends TypeSafeMatcher<TestObject> {
      private final String expectedValue;
    
      public IsATestObjectWithValue(String expectedValue) {
        super(TestObject.class);
        this.expectedValue = expectedValue;
      }
    
      @Override public void matchesSafely(TestObject object) {
        // object will never be null, but object.value might.
        return expectedValue.equals(object.value);
      }
    }
    
  • 使用答案。匿名的内部答案很常见,也很简洁,你可以访问所有的论点。这对于一次性解决方案尤其有用,或者如果您希望在传入无效值(testObject.value)时显式且立即使测试失败

  • 最后,如果调用的顺序是可预测的,则可以按顺序返回多个值

    when(collaborator.attemptToMock(any(TestObject.class)))
        .thenReturn(array1).thenReturn(array2);
    when(collaborator.attemptToMock(any(TestObject.class)))
        .thenReturn(array1, array2);  // equivalent
    
    对于第一次调用,上述任一行都将返回
    array1
    ;对于第二次调用以及之后的所有调用,无论参数如何,都将返回
    array2
    。此解决方案将比原始问题所要求的更为脆弱,如果调用顺序发生变化,或者如果其中任何一个调用被删除或重复,则此解决方案将失败。但是,如果测试是非常临时的,或者如果顺序是绝对固定的,则此解决方案有时是最紧凑的解决方案

when(collaborator.attemptToMock(any(TestObject.class)))
    .thenReturn(array1).thenReturn(array2);
when(collaborator.attemptToMock(any(TestObject.class)))
    .thenReturn(array1, array2);  // equivalent