gpt4 book ai didi

java - 模仿;验证方法是用列表调用的,忽略列表中元素的顺序

转载 作者:太空狗 更新时间:2023-10-29 22:33:49 26 4
gpt4 key购买 nike

我有一个类 (ClassA) 可以获取目录中的文件。它扫描给定目录以查找与正则表达式匹配的文件。对于每个匹配的文件,它将一个文件对象添加到列表中。一旦目录被处理,它将文件列表传递给另一个类(ClassB)进行处理

我正在为 ClassA 编写单元测试,因此我使用 Mockito 模拟 ClassB,并将其注入(inject) ClassA。然后我想在不同的场景中验证传递给 ClassB 的列表的内容(即我的模拟)

我已将代码剥离为以下内容

public class ClassA implements Runnable {

private final ClassB classB;

public ClassA(final ClassB classB) {
this.classB = classB;
}

public List<File> getFilesFromDirectories() {
final List<File> newFileList = new ArrayList<File>();
// ...
return newFileList;
}

public void run() {
final List<File> fileList = getFilesFromDirectories();

if (fileList.isEmpty()) {
//Log Message
} else {
classB.sendEvent(fileList);
}
}
}

测试类是这样的

    @RunWith(MockitoJUnitRunner.class)
public class AppTest {

@Rule
public TemporaryFolder folder = new TemporaryFolder();

@Mock
private ClassB mockClassB;

private File testFileOne;

private File testFileTwo;

private File testFileThree;

@Before
public void setup() throws IOException {
testFileOne = folder.newFile("testFileA.txt");
testFileTwo = folder.newFile("testFileB.txt");
testFileThree = folder.newFile("testFileC.txt");
}

@Test
public void run_secondFileCollectorRun_shouldNotProcessSameFilesAgainBecauseofDotLastFile() throws Exception {
final ClassA objUndertest = new ClassA(mockClassB);

final List<File> expectedFileList = createSortedExpectedFileList(testFileOne, testFileTwo, testFileThree);
objUndertest.run();

verify(mockClassB).sendEvent(expectedFileList);
}

private List<File> createSortedExpectedFileList(final File... files) {
final List<File> expectedFileList = new ArrayList<File>();
for (final File file : files) {
expectedFileList.add(file);
}
Collections.sort(expectedFileList);
return expectedFileList;
}
}

问题是这个测试在 windows 上工作得很好,但在 Linux 上失败了。原因是在 Windows 上,ClassA 列出文件的顺序与 expectedList 匹配,所以行

verify(mockClassB).sendEvent(expectedFileList);

在 Windows 上导致问题 expecetdFileList = {FileA, FileB, FileC},而在 Linux 上它将是 {FileC, FileB, FileA},因此验证失败。

问题是,我如何在 Mockito 中解决这个问题。有没有一种说法,我希望用这个参数调用这个方法,但我不关心列表内容的顺序。

我确实有一个解决方案,我只是不喜欢它,我宁愿有一个更清晰、更易于阅读的解决方案。

我可以使用 ArgumentCaptor 获取传递到模拟中的实际值,然后对其进行排序,并将其与我的预期值进行比较。

    final ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
verify(mockClassB).method(argument.capture());
Collections.sort(expected);
final List<String> value = argument.getValue();
Collections.sort(value);
assertEquals(expecetdFileList, value);

最佳答案

如另一个答案所述,如果您不关心订单,您最好更改界面,使其不关心订单。

如果顺序在代码中很重要,但在特定测试中不重要,您可以像以前一样使用 ArgumentCaptor。它使代码有点困惑。

如果这是你可能在多个测试中做的事情,你最好使用适当的 Mockito MatchersHamcrest Matchers ,或推出自己的(如果找不到满足需求的)。 hamcrest 匹配器可能是最好的,因为它可以在 mockito 之外的其他上下文中使用。

对于这个例子,你可以创建一个 hamcrest 匹配器,如下所示:

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyMatchers {
public static <T> Matcher<List<T>> sameAsSet(final List<T> expectedList) {
return new BaseMatcher<List<T>>(){
@Override
public boolean matches(Object o) {
List<T> actualList = Collections.EMPTY_LIST;
try {
actualList = (List<T>) o;
}
catch (ClassCastException e) {
return false;
}
Set<T> expectedSet = new HashSet<T>(expectedList);
Set<T> actualSet = new HashSet<T>(actualList);
return actualSet.equals(expectedSet);
}

@Override
public void describeTo(Description description) {
description.appendText("should contain all and only elements of ").appendValue(expectedList);
}
};
}
}

然后验证码变成:

verify(mockClassB).sendEvent(argThat(MyMatchers.sameAsSet(expectedFileList)));

如果您改为创建 mockito 匹配器,则不需要 argThat,它基本上将 hamcrest 匹配器包装在 mockito 匹配器中。

这将排序或转换的逻辑移出测试并使其可重用。

关于java - 模仿;验证方法是用列表调用的,忽略列表中元素的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25700059/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com