使用Mockito模拟方法行为时以任意顺序匹配列表

yv5phkfx  于 2022-11-08  发布在  其他
关注(0)|答案(4)|浏览(152)

我有一个使用Mockito的测试,它有一个非常奇怪的行为:它在调试时可以工作,但在正常运行时失败。经过一些调查,我意识到这是因为我在模拟方法的行为,传递了一个要匹配的元素列表。但由于某种原因,列表中的顺序并不总是相同的,所以它不匹配,我期望我的模拟返回的内容没有返回,因为这两个列表不“相等”。

when(mockStatusCalculatorService.calculateStatus(Arrays.asList(IN_PROGRESS, ABANDONNED,EXPIRED))).thenReturn(ConsolidatedStatus.EXPIRED);

在我的例子中,匹配元素的顺序并不重要,那么在配置mock时如何指定呢?

gcxthw6b

gcxthw6b1#

为Mockito和Java 8的较新版本添加答案

when(
   mock.method(argThat(t -> t.containsAll(Arrays.asList(IN_PROGRESS, ABANDONED, EXPIRED))))
).thenReturn(myValue);
sf6xfgos

sf6xfgos2#

如果您的Mockito版本低于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-core/2.1.0/org/mockito/ArgumentMatcher.html

icnyk63a

icnyk63a3#

这其实很简单。我们需要一个自定义匹配器:

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

fkvaft9z4#

如果顺序无关紧要,请更改StatusCalculator服务以接受Set而不是Collection。这样,equals将返回true而不考虑顺序。
最好是修复你的API,而不是在单元测试中绕过它。

相关问题