我有一个包含ToString
方法的类,可以生成XML。我希望对其进行单元测试以确保它生成的是有效的XML。我有一个DTD文件用来验证XML。
我应该将DTD作为字符串包含在单元测试中,以避免对其产生依赖性,或者有更聪明的方法可以做到这一点吗?
我有一个包含ToString
方法的类,可以生成XML。我希望对其进行单元测试以确保它生成的是有效的XML。我有一个DTD文件用来验证XML。
我应该将DTD作为字符串包含在单元测试中,以避免对其产生依赖性,或者有更聪明的方法可以做到这一点吗?
如果您的程序在正常执行期间针对DTD验证XML,则应该从程序获取DTD。
如果不是这样,并且DTD非常短(仅有几行),那么将其作为字符串存储在代码中可能是可以的。
否则,我建议将其放在外部文件中,并让您的单元测试从该文件中读取它。
我以前使用过XmlUnit,发现它非常有用。
它可以用于针对模式验证XML或将您的XML与字符串进行比较。它足够聪明以理解XML的解析规则。 例如,它知道"<e1/>"相当于"<e1></e1>",并且可以配置为忽略或包含空格。
在单元测试中使用DTD来测试其有效性是一回事,测试正确内容是另一回事。
您可以使用DTD来检查生成的XML的有效性,就像在程序中读取的方式一样。我个人不会将其内联(作为字符串)包含在内;您的应用程序代码和单元测试之间总是存在依赖关系。当生成的XML发生变化时,DTD也会发生变化。
要测试正确的内容,我会选择使用XMLUnit。
使用XMLUnit进行XML断言:
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
Diff diff = new Diff(expectedDocument, obtainedDocument);
XMLAssert.assertXMLIdentical("xml invalid", diff, true);
你可能会遇到的一个问题是生成的 XML 可能包含变化的标识符(如 id/uid 属性等)。可以通过在断言生成的 XML 时使用 DifferenceListener 来解决这个问题。
以下是这种 DifferenceListener 的示例实现:
public class IgnoreVariableAttributesDifferenceListener implements DifferenceListener {
private final List<String> IGNORE_ATTRS;
private final boolean ignoreAttributeOrder;
public IgnoreVariableAttributesDifferenceListener(List<String> attributesToIgnore, boolean ignoreAttributeOrder) {
this.IGNORE_ATTRS = attributesToIgnore;
this.ignoreAttributeOrder = ignoreAttributeOrder;
}
@Override
public int differenceFound(Difference difference) {
// for attribute value differences, check for ignored attributes
if (difference.getId() == DifferenceConstants.ATTR_VALUE_ID) {
if (IGNORE_ATTRS.contains(difference.getControlNodeDetail().getNode().getNodeName())) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
}
// attribute order mismatch (optionally ignored)
else if (difference.getId() == DifferenceConstants.ATTR_SEQUENCE_ID && ignoreAttributeOrder) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
// attribute missing / not expected
else if (difference.getId() == DifferenceConstants.ATTR_NAME_NOT_FOUND_ID) {
if (IGNORE_ATTRS.contains(difference.getTestNodeDetail().getValue())) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
}
return RETURN_ACCEPT_DIFFERENCE;
}
@Override
public void skippedComparison(Node control, Node test) {
// nothing to do
}
}
使用 DifferenceListener:
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
Diff diff = new Diff(expectedDocument, obtainedDocument);
diff.overrideDifferenceListener(new IgnoreVariableAttributesDifferenceListener(Arrays.asList("id", "uid"), true));
XMLAssert.assertXMLIdentical("xml invalid", diff, true);