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

时间:2008-09-09 12:46:21

标签: xml unit-testing language-agnostic dtd

我有一个使用ToString方法生成XML的类。我想对它进行单元测试,以确保它生成有效的xml。我有一个DTD来验证XML。

我应该在单元测试中将DTD作为字符串包含在内以避免依赖,还是有更智能的方法来执行此操作?

3 个答案:

答案 0 :(得分:6)

如果您的程序在正常执行期间针对DTD验证XML,那么您应该从程序获取DTD的任何地方获取DTD。

如果没有并且DTD非常短(只有几行),那么将其作为字符串存储在代码中可能没问题。

否则,我会把它放在一个外部文件中,让你的单元测试从那个文件读取它。

答案 1 :(得分:6)

我过去曾使用XmlUnit并发现它很有用。

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

答案 2 :(得分: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);