XMLUnit 嵌套元素测试
XMLUnit nested element testing
我有两个 XML 文件要比较。我正在使用 XMLUnit 2。但是元素可能是无序的(包括子元素排序)下面的所有三个示例都需要被视为等效:
<Product>
<Property>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
<Container value="5">Test 03</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
</Product>
<Product>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Product>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
</Product>
似乎 XMLUnit 应该能够很容易地做到这一点,但我不知道我需要做什么来配置测试。我应该补充一点,嵌套可以变得更深,因为容器下面有更多元素来证明同样的问题。
---
可能的解决方案:
public class SubNodeEqualityElementSelector implements ElementSelector {
public SubNodeEqualityElementSelector() {
}
@Override
public boolean canBeCompared(Element controlElement, Element testElement) {
// test input nodes for equality first.
if (!ElementSelectors.byNameAndAllAttributes.canBeCompared(controlElement, testElement)) {
return false;
}
if (!ElementSelectors.byNameAndText.canBeCompared(controlElement, testElement)) {
return false;
}
// test children for equality. For each ctrl child, make sure that a matching element is found in the test set.
ArrayList<Element> ctrlChildren = getChildElements(controlElement);
ArrayList<Element> testChildren = getChildElements(testElement);
ArrayList<Element> ctrlChildrenResults = new ArrayList<Element>(ctrlChildren);
ArrayList<Element> testChildrenResults = new ArrayList<Element>(testChildren);
for (Element ctrlChild : ctrlChildren) {
for (Element testChild : testChildren) {
if (ElementSelectors.byNameAndAllAttributes.canBeCompared(ctrlChild, testChild) &&
ElementSelectors.byNameAndText.canBeCompared(ctrlChild, testChild)) {
ctrlChildrenResults.remove(ctrlChild);
testChildrenResults.remove(testChild);
}
}
}
return ctrlChildrenResults.size() == 0 && testChildrenResults.size() == 0;
}
private ArrayList<Element> getChildElements(Element elem) {
ArrayList<Element> retVal = new ArrayList<Element>();
NodeList childNodes = elem.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element){
Element element = (Element) node;
retVal.add(element);
}
}
return retVal;
}
}
我测试了上面的 class (SubNodeEqualityElementSelector),它似乎运行良好!
这是一个相当困难的例子。
如果您想使用 XMLUnit 1.x 解决这个问题,那么您必须编写一个 ElementQualifier
代码,以便在面对列表时选择正确的 Property
元素。您必须自己编写,内置版本都不会。此外,您只能有一个 ElementQualifier
,因此您还需要处理剩余的比较,例如选择正确的 Container
- ElementNameAndAttributeQualifier
可以完成的事情。
使用 XMLUnit 2.x 并没有变得容易很多,但至少您可以使用条件构建器来组合 ElementSelector
。 https://github.com/xmlunit/user-guide/wiki/SelectingNodes 中的用户指南示例很接近,它根据第一个 "inner" 元素的嵌套文本选择正确的 "outer" 元素。在您的情况下,您似乎需要根据嵌套 Container
的属性来选择 Property
,但不幸的是,仅查看第一个 Container
是不够的。恐怕我们不会想出一个有效的 XPath,所以你可能仍然需要编写 Java 代码来选择正确的 Property
,但是一旦你得到了它,你就可以做一些事情喜欢
ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Property").thenUse(YOUR_ELEMENT_SELECTOR)
.elseUse(ElementSelectors.byNameAndAllAttributes)
.build();
我有两个 XML 文件要比较。我正在使用 XMLUnit 2。但是元素可能是无序的(包括子元素排序)下面的所有三个示例都需要被视为等效:
<Product>
<Property>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
<Container value="5">Test 03</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
</Product>
<Product>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Product>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
</Product>
似乎 XMLUnit 应该能够很容易地做到这一点,但我不知道我需要做什么来配置测试。我应该补充一点,嵌套可以变得更深,因为容器下面有更多元素来证明同样的问题。
---
可能的解决方案:
public class SubNodeEqualityElementSelector implements ElementSelector {
public SubNodeEqualityElementSelector() {
}
@Override
public boolean canBeCompared(Element controlElement, Element testElement) {
// test input nodes for equality first.
if (!ElementSelectors.byNameAndAllAttributes.canBeCompared(controlElement, testElement)) {
return false;
}
if (!ElementSelectors.byNameAndText.canBeCompared(controlElement, testElement)) {
return false;
}
// test children for equality. For each ctrl child, make sure that a matching element is found in the test set.
ArrayList<Element> ctrlChildren = getChildElements(controlElement);
ArrayList<Element> testChildren = getChildElements(testElement);
ArrayList<Element> ctrlChildrenResults = new ArrayList<Element>(ctrlChildren);
ArrayList<Element> testChildrenResults = new ArrayList<Element>(testChildren);
for (Element ctrlChild : ctrlChildren) {
for (Element testChild : testChildren) {
if (ElementSelectors.byNameAndAllAttributes.canBeCompared(ctrlChild, testChild) &&
ElementSelectors.byNameAndText.canBeCompared(ctrlChild, testChild)) {
ctrlChildrenResults.remove(ctrlChild);
testChildrenResults.remove(testChild);
}
}
}
return ctrlChildrenResults.size() == 0 && testChildrenResults.size() == 0;
}
private ArrayList<Element> getChildElements(Element elem) {
ArrayList<Element> retVal = new ArrayList<Element>();
NodeList childNodes = elem.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element){
Element element = (Element) node;
retVal.add(element);
}
}
return retVal;
}
}
我测试了上面的 class (SubNodeEqualityElementSelector),它似乎运行良好!
这是一个相当困难的例子。
如果您想使用 XMLUnit 1.x 解决这个问题,那么您必须编写一个 ElementQualifier
代码,以便在面对列表时选择正确的 Property
元素。您必须自己编写,内置版本都不会。此外,您只能有一个 ElementQualifier
,因此您还需要处理剩余的比较,例如选择正确的 Container
- ElementNameAndAttributeQualifier
可以完成的事情。
使用 XMLUnit 2.x 并没有变得容易很多,但至少您可以使用条件构建器来组合 ElementSelector
。 https://github.com/xmlunit/user-guide/wiki/SelectingNodes 中的用户指南示例很接近,它根据第一个 "inner" 元素的嵌套文本选择正确的 "outer" 元素。在您的情况下,您似乎需要根据嵌套 Container
的属性来选择 Property
,但不幸的是,仅查看第一个 Container
是不够的。恐怕我们不会想出一个有效的 XPath,所以你可能仍然需要编写 Java 代码来选择正确的 Property
,但是一旦你得到了它,你就可以做一些事情喜欢
ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Property").thenUse(YOUR_ELEMENT_SELECTOR)
.elseUse(ElementSelectors.byNameAndAllAttributes)
.build();