学习使用 XmlUnit 2.x来测试和验证XML文档的简单易懂的例子。XmlUnit要求我们准确地知道我们要验证的XML内容与一个给定的测试XML进行比较。
对于断言,我们使用Hamcrest匹配器库。
目录
1.Maven的依赖性
将最新版本的xmlunit-core和xmlunit-matchers依赖项纳入项目。
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-matchers</artifactId>
<version>2.9.0</version>
</dependency>
<!-- If using Hamcrest matchers -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
</dependency>
2.读取和比较XML源
2.1.读取XML源
为了进行比较,XmlUnit的CompareMatcher ,可以从各种来源获取输入,如。
java.lang.Stringjava.io.Filejava.io.InputStreamjava.io.Readerbyte arrayorg.w3c.dom.Document等。
下面的代码演示了用不同的方式来读取一个文件widget.xml。
@Test
void createSource_ThenSuccess() throws ParserConfigurationException, IOException, SAXException {
//1 - Using File
Input.from(new File("widget.xml"));
Input.fromFile("widget.xml");
Input.fromFile(getClass().getClassLoader().getResource("widget.xml").getPath());
//2 - Using String
Input.from("<widget><id>1</id><name>demo</name></widget>");
Input.fromString("<widget><id>1</id><name>demo</name></widget>");
//3 - Using Stream
Input.from(XmlUnitExamples.class.getResourceAsStream("widget.xml"));
Input.fromStream(XmlUnitExamples.class.getResourceAsStream("widget.xml"));
//4 - From Reader
Input.from(new StringReader("<widget><id>1</id><name>demo</name></widget>"));
Input.fromReader(new StringReader("<widget><id>1</id><name>demo</name></widget>"));
//5 - From Byte Array
Input.from("<widget><id>1</id><name>demo</name></widget>".getBytes());
Input.fromByteArray("<widget><id>1</id><name>demo</name></widget>".getBytes());
//6 - From Document
DocumentBuilder b = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = b.parse(new File("widget.xml"));
Input.from(document);
Input.fromDocument(document);
}
2.2.比较XML来源
我们可以用各种方式比较两个XML。在下面的例子中,我们正在比较两个XML字符串。
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String controlXml = "<widget><id>1</id><name>demo</name></widget>";
assertThat(testXml, isIdenticalTo(identicalXml));
同样地,在下一个例子中,我们正在比较两个XML文件。
assertThat(new File("widget.xml"), isIdenticalTo(identicalXml));
assertThat(new File("widget.xml"), isIdenticalTo(new File("otherFile.xml")));
我们可以在比较中 混合不同类型的源。
assertThat(new File("widget.xml"), isIdenticalTo(Input.from(identicalXml)));
3.使用XmlUnit的比较实例
让我们检查一下使用XmlUnit比较两个XML的不同方法。
3.1.比较相同的XMLs
当两个XML具有完全相同的内容时,即两个XML具有相同的标签、相同的顺序和相同的值时,它们被认为是相同的。
下面的例子使用CompareMatcher的静态方法来比较两个XMLs。
@Test
void compareIdenticalAndSimilarXmlWithHamcrest_ThenSuccess() throws Exception {
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String identicalXml = "<widget><id>1</id><name>demo</name></widget>";
String nonIdenticalXml = "<widget><name>demo</name><id>1</id></widget>";
assertThat(testXml, isIdenticalTo(identicalXml));
assertThat(testXml, not(isIdenticalTo(nonIdenticalXml)));
}
我们还可以DiffBuilder API,收集两个XML之间的所有差异。DiffBuilder是一个流畅的API,可以以一种更可控的方式获得差异。
@Test
void compareIdenticalAndSimilarXmlDiff_ThenSuccess() throws Exception {
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String identicalXml = "<widget><id>1</id><name>demo</name></widget>";
Diff diffForIdentical = DiffBuilder
.compare(testXml)
.withTest(identicalXml)
.checkForIdentical()
.build();
assertThat(IterableUtils.size(diffForIdentical.getDifferences()), equalTo(0));
}
3.2.比较相似的XMLs
当两个XML具有相同的标签和值,但标签的顺序不同时,就可以认为它们是相似的。在下面的例子中,nonIdenticalXml有类似的标签,但是id和name的顺序不同。
默认情况下,XmlUnit使用 DefaultNodeMatcher匹配从根标签开始的相同深度的XML标签,并以相同的顺序。要让XmlUnit忽略这个顺序,我们使用 ElementSelectors.byName在开始匹配之前,按名称对所有标签进行相同深度的排序。
@Test
void compareIdenticalAndSimilarXmlWithHamcrest_ThenSuccess() throws Exception {
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String nonIdenticalXml = "<widget><name>demo</name><id>1</id></widget>";
assertThat(testXml, isSimilarTo(nonIdenticalXml)
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName)));
}
类似地,我们可以使用ElementSelectors.byName与DiffBuilderAPI。
@Test
void compareIdenticalAndSimilarXmlDiff_ThenSuccess() throws Exception {
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String nonIdenticalXml = "<widget><name>demo</name><id>1</id></widget>";
Diff diffForSimilarity = DiffBuilder
.compare(testXml)
.withTest(nonIdenticalXml)
.checkForSimilar()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName))
.build();
assertThat(IterableUtils.size(diffForSimilarity.getDifferences()), equalTo(0));
}
3.3.比较或忽略特定标签
在匹配XML时,可能需要忽略特定的标签或只比较几个特定的标签。我们可以通过以下方法来实现 ***withNodeFilter()***方法来实现。这个方法将为XML中的每个节点被调用。如果该方法返回true,那么将进行比较,否则跳过。
在下面的XML中,只有id标签将被比较。name标签将被跳过。我们可以通过在*withNodeFilter()*方法中创建一个复杂的表达式来包括或排除任何数量的标签。
@Test
void compareOnlySpecificTags_ThenSuccess() {
String testXml = "<widget><id>1</id><name>test</name></widget>";
String otherXml = "<widget><name>live</name><id>1</id></widget>";
Diff diffs = DiffBuilder.compare(testXml)
.withTest(otherXml)
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName))
.withNodeFilter(
node -> node.getNodeName().equalsIgnoreCase("id")
)
.build();
assertThat(IterableUtils.size(diffs.getDifferences()), equalTo(0));
}
3.4.使用XPaths进行比较
在所有情况下,比较整个XML是不可行的。如果我们只想比较XML的一个特定部分,我们可以使用XPath表达式。
@Test
void containsAsChildXmlUsingXPath_ThenSuccess() throws Exception {
String fullXml = "<widget><id>1</id><name>demo</name></widget>";
//Contains 'id' tag
assertThat(fullXml, HasXPathMatcher.hasXPath("/widget/id"));
//Compare value of 'id' tag
assertThat(fullXml, EvaluateXPathMatcher.hasXPath("/widget/id/text()", equalTo("1")));
}
4.规范化的XMLs
收到的XML可能并不总是规范化和干净的。我们可以使用两种方法对XML进行规范化。
4.1.使用源码装饰器
XmlUnit提供了以下装饰器,我们可以在第一节中与Source实例构建一起使用。
CommentLessSource:提供由原始源的内容组成的XML,并删除所有的注释。WhitespaceStrippedSource: 删除所有的空文本节点并修剪剩余的文本节点。有效地,它从XML中删除了所有的空字符串,包括节点内容。WhitespaceNormalizedSource替换:用Space字符替换文本节点中发现的所有空白字符,并将连续的空白字符折叠成一个Space。NormalizedSource:相邻的文本节点被合并为单个节点,并删除空的文本节点(递归)。ElementContentWhitespaceStrippedSource空白:删除所有仅由空白组成的文本节点。它删除了所有的 "元素内容空白",即XML元素之间的文本内容,这只是 "漂亮打印 "XML的一个伪装。
@Test
void normalizedXmlSources_ThenSuccess() throws Exception {
CommentLessSource commentLessSource
= new CommentLessSource(Input.fromFile("widget.xml").build());
WhitespaceStrippedSource whitespaceStrippedSource
= new WhitespaceStrippedSource(Input.fromFile("widget.xml").build());
WhitespaceNormalizedSource whitespaceNormalizedSource
= new WhitespaceNormalizedSource(Input.fromFile("widget.xml").build());
ElementContentWhitespaceStrippedSource elementContentWhitespaceStrippedSource
= new ElementContentWhitespaceStrippedSource(Input.fromFile("widget.xml").build());
}
4.2.使用CompareMatcher
另一种规范化XML的方法是使用CompareMatcher类提供的工厂方法,同时比较两种XML内容。
@Test
void normalizedXmlMatchers_ThenSuccess() throws Exception {
String testXml = "<widget><id>1</id><name>demo</name></widget>";
String identicalXml = "<widget><id>1</id><name>demo</name></widget>";
assertThat(testXml, isIdenticalTo(identicalXml).normalizeWhitespace());
assertThat(testXml, isIdenticalTo(identicalXml).ignoreComments());
}
5.总结
在这个XmlUnit 2.x教程中,我们学会了创建不同类型的XML源,用装饰器进行规范化,用XPath比较相同、相似和片段。
祝你学习愉快!!。
这个帖子有帮助吗?
如果你喜欢这篇文章,请告诉我们。这是我们改进的唯一方法。
有
没有