1

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

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

public ArrayList<example> attemptToMock(testObject testing)

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

因此,如果 testObject 中的字符串值为“OK”,那么attemptToMock应该在其中输出一个包含两个对象的数组。如果testObject字符串值为“NO”,则发出的 Array 列表只有一个 Object。

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

4

2 回答 2

3

几个选项:

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

    // Mockito compares with objects' equals(Object) methods by default.
    when(collaborator.attemptToMock(object1)).thenReturn(array1);
    when(collaborator.attemptToMock(object2)).thenReturn(array2);
    
  • 编写一个Hamcrest 匹配器并使用它来匹配数组。这充当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);
    
  • 使用答案,如 wdf 所述。匿名内部答案很常见且非常简洁,您可以访问所有参数。这对于一次性解决方案特别有用,或者如果您想在传入无效值 (testObject.value) 时显式地立即使测试失败。

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

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

    无论参数如何,上述任何一行都将返回array1第一次调用和array2第二次调用以及之后的所有调用。该解决方案将比您最初的问题要求的要脆弱得多-如果调用顺序发生更改,或者如果其中一个调用被编辑或重复,它将失败-但有时如果测试非常紧凑,则它是最紧凑的解决方案临时的或者如果订单是绝对固定的。

于 2015-02-04T18:24:30.497 回答
0

您可以使用 Answer 接口访问传递给模拟方法调用的参数并相应地改变返回值。请参阅此问题的答案以及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);
}
于 2015-02-04T00:58:59.127 回答