我使用的测试使用了一个非常奇怪的行为:它在调试中起作用,但在正常运行时失败。经过一番调查,我意识到这是因为我嘲笑方法行为,传递了要匹配的元素列表。但是由于某种原因,列表中的顺序并不总是相同的,因此它不匹配,我希望我的模拟不会返回,因为两个列表不是"等于"
when(mockStatusCalculatorService.calculateStatus(Arrays.asList(IN_PROGRESS, ABANDONNED,EXPIRED))).thenReturn(ConsolidatedStatus.EXPIRED);
在我的情况下,要匹配的元素顺序无关紧要。那么,在配置模拟时,该如何指定呢?
添加了Mockito和Java 8
的新版本的答案when(
mock.method(argThat(t -> t.containsAll(Arrays.asList(IN_PROGRESS, ABANDONED, EXPIRED))))
).thenReturn(myValue);
如果您在版本2.1.0之前有摩擦脚:
使用hamcrest containsInAnyOrder
匹配器。
when(myMock.myMethod(argThat(containsInAnyOrder(IN_PROGRESS, ABANDONED, EXPIRED))))
.thenReturn(myValue);
谢谢@kolobok指出的是,从Mockito 2.1.0(我写了这个答案之后出现),这不再有效。
因此,版本2.1.0及以上:
添加对Hamcrest的依赖性,并使用MockitoHamcrest.argThat
代替Mockito.argThat
使用Mockito 2.1.0的破坏变化的更多详细信息在https://www.javadoc.io/doc/org.mockito/mockito/mockito-core/2.1.0/org/org/mockito/mockito/argumentMather.argumentMather.htmather.htmather.html
实际上很简单。我们需要一个自定义匹配器:
import org.apache.commons.collections.CollectionUtils;
import org.mockito.ArgumentMatcher;
import java.util.List;
import static org.mockito.Matchers.argThat;
public class InAnyOrderListMatcher extends ArgumentMatcher<List> {
private final List expected;
public InAnyOrderListMatcher(List expected){
this.expected=expected;
}
@Override
public boolean matches(Object actual) {
if(actual instanceof List){
List actualList=(List)actual;
return CollectionUtils.isEqualCollection(expected,actualList);
}
return false;
}
public static List inAnyOrderListMatcherEq(List expected) {
return argThat(new InAnyOrderListMatcher(expected));
}
}
然后在测试中调用它:
when(mockStatusCalculatorService.calculateStatus( inAnyOrderListMatcherEq(Arrays.asList(IN_PROGRESS, ABANDONNED,EXPIRED)))).thenReturn(ConsolidatedStatus.EXPIRED);
如果订单无关紧要,请更改您的状态计算器服务以接受集合而不是集合。然后,无论秩序如何,平等将返回真实。
修复API比在单元测试中围绕它进行入侵更好。