Mockito Mock调用两次方法调用

时间:2015-02-03 23:32:25

标签: java unit-testing junit mockito springmockito

我正在尝试使用mockito来模拟方法。但是我注入模拟的类在调用两个相同类型的不同对象时调用该方法两次,但是根据对象中的值确定方法的输出。

所以,例如,如果我想模拟

public ArrayList<example> attemptToMock(testObject testing)

让sat sat type testObject中有一个字符串值。

因此,如果testObject中的字符串值为&#34; OK&#34;那么attemptToMock应该输出一个包含两个对象的数组。如果testObject字符串值是&#34;否则&#34;然后发出的数组列表只有一个对象。

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

2 个答案:

答案 0 :(得分:2)

一些选择:

    您对象上的
  • Override equals and hashCode(TestObject)。这只有在对象上的所有值都是可预测的情况下才可行,并且可能比其他解决方案更有效,但是如果您还需要编写equalshashCode(对于Map和Set行为,对于例如)这是一个合理的解决方案。

    // Mockito compares with objects' equals(Object) methods by default.
    when(collaborator.attemptToMock(object1)).thenReturn(array1);
    when(collaborator.attemptToMock(object2)).thenReturn(array2);
    
  • 写一个Hamcrest matcher并使用它来匹配数组。对于特定情况,这可以作为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);
      }
    }
    

    现在您可以编写如上所述的等效匹配:

    when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("OK")))
        .thenReturn(array1);
    when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("NO")))
        .thenReturn(array2);
    
  • 使用答案as wdf described。匿名内部答案很常见且非常简洁,您可以访问所有参数。这对于一次性解决方案尤其有用,或者如果您希望在传入无效值(testObject.value)时显式地立即使测试失败。

  • 作为最后的手段,如果调用的顺序是可预测的,您可以按顺序返回多个值。

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

    上述任何一行都会在第一次通话时返回array1,在第二次通话时返回array2,并且无论参数如何,都会返回所有通话。此解决方案比原始问题要强得多<强> - 如果呼叫顺序发生变化,或者如果其中一个呼叫被删除或重复,它将失败 - 但有时最多紧凑的解决方案,如果测试非常临时或订单是绝对修复的。

答案 1 :(得分:0)

您可以访问传递给模拟方法调用的参数,并使用Answer接口相应地改变返回值。请参阅this question的答案和the docs for Answer

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

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);
}