[英]JUnit ~ Assert that list contains objects with the same values in any order
我的用例是我正在编写一个文档解析器(用于 ReqIF 文档)并且想要比较解析的对象是否包含预期的元素。 为此,我想编写一个 JUnit 测试。
实际上,我正在寻找的是一种断言方法,该方法将两个对象列表与值进行比较,并在两个列表都包含(以任何顺序)与引用列表具有相同值的对象时通过。
为了抽象,考虑这个例子:
Apple referenceApple1 = new Apple(color="red");
Apple referenceApple2 = new Apple(color="green");
Apple parsedApple1 = new Apple(color="red");
Apple parsedApple2 = new Apple(color="green");
Apple badApple = new Apple(color="brown");
List<Apple> referenceList = new List<Apple>(referenceApple1, referenceApple2);
List<Apple> correctlyParsedList1 = new List<Apple>(parsedApple1, parsedApple2);
List<Apple> correctlyParsedList2 = new List<Apple>(parsedApple2, parsedApple1);
List<Apple> wronglyParsedList1 = new List<Apple>(parsedApple1, badApple);
List<Apple> wronglyParsedList2 = new List<Apple>(parsedApple1, parsedApple2, parsedApple1);
List<Apple> wronglyParsedList3 = new List<Apple>(parsedApple2, parsedApple2);
我在寻找一个比较上述任何时候通过断言方法correctlyParsedList*
与referenceList
,但对比上述任何失败时wronglyParsedList*
与referenceList
。
目前,我最接近的是这个:
assertEquals(referenceList.toString(), correctlyParsedList1.toString())
但是,只要对象处于另一个顺序,这就会失败。
//Will fail, but I want a method that will compare these and pass
assertEquals(referenceList.toString(), correctlyParsedList2.toString())
值得注意的是,以下内容也会失败,因为 Apple 虽然包含相同的值,但不是同一对象的实例:
assertThat(correctlyParsedList1, is(referenceList));
//Throws This error:
java.lang.AssertionError:
Expected: is <[[color="red"], [color="green"]]>
but: was <[[color="red"], [color="green"]]>
有没有一种简单的方法可以在 JUnit 中做出这样的断言? 我知道我可以为此迭代对象编写自定义断言方法,但不知何故,感觉这将是一个常见用例,应该有一个预定义的断言方法,该方法会引发表达性断言错误。
编辑~具体化
我实际上试图用这个抽象示例做的是使用 JDOM2 解析一个复杂的 XML,我想断言被解析的标签的属性等于我作为输入提供的示例文档中存在的属性。 由于这是 XML,属性的顺序无关紧要,只要它们具有正确的值即可。
如此有效,我在这个实际用例中比较的是两个List<Attribute>
,其中Attribute
来自org.jdom2.Attribute
。
我目前不满意的完整临时测试用例,因为如果属性顺序更改但不应该更改,它将失败,如下所示:
@Test
public void importXML_fromFileShouldCreateXML_objectWithCorrectAttributes() throws JDOMException, IOException {
testInitialization();
List<Attribute> expectedAttributes = rootNode.getAttributes();
XML_data generatedXML_data = xml_importer.importXML_fromFile(inputFile);
List<Attribute> actualAttributes = generatedXML_data.attributes;
assertEquals(expectedAttributes.toString(), actualAttributes.toString());
}
尝试使用assertThat(expectedAttributes, is(actualAttributes))
进行断言时遇到的具体错误是:
java.lang.AssertionError:
Expected: is <[[Attribute: xsi:schemaLocation="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd http://www.omg.org/spec/ReqIF/20110401/reqif.xsd"], [Attribute: xml:lang="en"]]>
but: was <[[Attribute: xsi:schemaLocation="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd http://www.omg.org/spec/ReqIF/20110401/reqif.xsd"], [Attribute: xml:lang="en"]]>
您应该使用containsAll
来检查一个列表是否containsAll
另一个列表中的所有项目,只要您的Apple
有适当的 equals 实现,这应该可以工作:
// Covers case where all items that are from correct list are in reference as well
// but also some additional items exist that are not in correct list
assertEquals(correctlyPassedList.size(), referenceList.size());
// Checks if each element is contained in list
assertTrue(referenceList.containsAll(correctlyPassedList));
更新
关于您的最新评论,这可能最有效:
// Sort both lists using comparator based on id or whatever field is relevant
referenceList.sort(Comparator.comparingInt(Apple::getId));
correctlyParsedList.sort(Comparator.comparingInt(Apple::getId));
// Check if they are equal
assertEquals(correctlyParsedList, referenceList);
如果你不关心元素的顺序,你可以在比较它们之前对列表进行排序。
我个人更喜欢始终使用AssertJ 。
import static org.assertj.core.api.Assertions.assertThat;
这两个断言中的任何一个都应该可以解决问题!
assertThat(correctlyParsedList1).containsOnlyOnce(referenceApple1, referenceApple2);
assertThat(correctlyParsedList1).containsOnlyOnceElementsOf(referenceList);
根据@FilipRistic 的回答,这对我有用:
使用基于id
或任何相关字段的比较器对两个列表进行排序:
referenceList.sort(Comparator.comparingInt(Apple::getId));
correctlyParsedList.sort(Comparator.comparingInt(Apple::getId));
然后简单地:
assertThat(referenceList).usingRecursiveComparison().isEqualTo(correctlyParsedList);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.