在单元测试中验证XML的最佳方法是什么?

10

我有一个包含ToString方法的类,可以生成XML。我希望对其进行单元测试以确保它生成的是有效的XML。我有一个DTD文件用来验证XML。

我应该将DTD作为字符串包含在单元测试中,以避免对其产生依赖性,或者有更聪明的方法可以做到这一点吗?

3个回答

6

如果您的程序在正常执行期间针对DTD验证XML,则应该从程序获取DTD。

如果不是这样,并且DTD非常短(仅有几行),那么将其作为字符串存储在代码中可能是可以的。

否则,我建议将其放在外部文件中,并让您的单元测试从该文件中读取它。


DTD 应该本地存储,这样单元测试就不依赖于网络服务是否可用。 - Thorbjørn Ravn Andersen

6

我以前使用过XmlUnit,发现它非常有用。

它可以用于针对模式验证XML或将您的XML与字符串进行比较。它足够聪明以理解XML的解析规则。 例如,它知道"<e1/>"相当于"<e1></e1>",并且可以配置为忽略或包含空格。


感谢提供 XmlUnit 的链接,听起来很有趣且有帮助。 - Vin

0

在单元测试中使用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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接