Doc4j:由于元素类型不同,比较两个文档失败
Doc4j: Compare two documents fails due to different Element-types
我尝试为我编写的 Docx4J 生成器编写一些 JUnit 测试。
我想将我的生成器的输出节点与我想从字符串加载的预期节点进行比较。
所以,我像这样创建 "actual" 节点(生成器输出):
Node xmlNodeActual = XmlUtils.marshaltoW3CDomDocument(actual).getDocumentElement();
其中 "actual" 是我的生成器创建的对象。
对于我的 "expected" 节点,我编写了以下代码:
Document doc = docBuilder.parse(new InputSource(new ByteArrayInputStream(strXmlNode.getBytes("utf-8")))):
Node xmlNodeExpected = doc.getDocumentElement();
strXmlNode 是一个包含预期 xml 的字符串。
尽管我从视觉差异中可以看出我的两个节点是相等的,但调用以下结果会产生 'false':
xmlNodeActual.isEqualNode(xmlNodeExpected)
我怀疑原因是两个节点的运行时类型不同:
- xml实际节点:org.apache.xerces.dom.DeferredElementImpl
- xml预期节点:org.apache.xerces.dom.ElementNSImpl
我喜欢我的测试设计,因为它可以让我为大型生成器快速编写大量测试用例。但是,我看不到将这种方法与 "isEqualNode" 结合使用的方法。
我是否必须编写自己的比较器,或者是否有一种我不知道的方法来确保节点的类型相同?
使用这样的方法的一个问题是它只给出一个布尔值答案,它不会告诉您两个节点之间的实际差异是什么。另一个问题是你无法告诉它你认为重要的差异是什么:例如(据我所知)冗余名称空间声明被这个特定的方法认为是重要的。空格通常是有问题的。我在使用 XPath deep-equal() 方法时遇到了同样的问题,结果写了 saxon:deep-equal 变体。但我现在更喜欢使用一组 XPath 断言来测试预期结果。 W3C XSLT 测试套件将此技术与测试断言一起使用,如下所示:
<result>
<all-of>
<assert>/root/p[1]/text()[1] = 'Tekst '</assert>
<assert>/root/p[1]/text()[2] = ' etc..'</assert>
<assert>/root/p[2]/text()[1] = 'Tekst '</assert>
<assert>/root/p[2]/text()[2] = ' etc..'</assert>
</all-of>
</result>
我曾经有一个小工具可以从 XML 文档中生成这样的断言列表,但现在我倾向于手动执行它们。最大的好处是,如果出现问题,诊断程序会告诉您哪个断言失败了。
您可能会考虑其他三种可能性:
请注意,@Michael Kay 和@JasonPlutext 提供了关于如何测试 XML 一般输出的有趣且更好的替代方案,您可能需要考虑。
至于我的具体问题,即简单地比较两个 XML 节点和 "isEqualNode",一个源于输入字符串,一个源于数据转换,我必须执行以下操作:我可以通过 InputStream 解组它,而不是解析字符串,从而获得所需的节点类型。
// creating the "actual" node I want to test (nothing changed here)
Node xmlNodeActual = XmlUtils.marshaltoW3CDomDocument(actual).getDocumentElement();
//...
// Instead of parsing the string, just unmarshal and marshal it once
Object expected = XmlUtils.unmarshal(new ByteArrayInputStream(strXmlNode.getBytes("utf-8")));
Node xmlNodeExpected = XmlUtils.marshaltoW3CDomDocument(expected).getDocumentElement();
if(!xmlNodeActual.isEqualNode(xmlNodeExpected)) {
// ...
}
这会产生相同的节点类型,并按预期适用于我的设置。不过,这种比较两棵 XML 树的方法有几个缺陷,正如 Michael Kay 所指出的,所以不要认为这是最佳实践,而是求助于另一个答案进行一般 XML 比较。
我尝试为我编写的 Docx4J 生成器编写一些 JUnit 测试。 我想将我的生成器的输出节点与我想从字符串加载的预期节点进行比较。
所以,我像这样创建 "actual" 节点(生成器输出):
Node xmlNodeActual = XmlUtils.marshaltoW3CDomDocument(actual).getDocumentElement();
其中 "actual" 是我的生成器创建的对象。
对于我的 "expected" 节点,我编写了以下代码:
Document doc = docBuilder.parse(new InputSource(new ByteArrayInputStream(strXmlNode.getBytes("utf-8")))):
Node xmlNodeExpected = doc.getDocumentElement();
strXmlNode 是一个包含预期 xml 的字符串。 尽管我从视觉差异中可以看出我的两个节点是相等的,但调用以下结果会产生 'false':
xmlNodeActual.isEqualNode(xmlNodeExpected)
我怀疑原因是两个节点的运行时类型不同:
- xml实际节点:org.apache.xerces.dom.DeferredElementImpl
- xml预期节点:org.apache.xerces.dom.ElementNSImpl
我喜欢我的测试设计,因为它可以让我为大型生成器快速编写大量测试用例。但是,我看不到将这种方法与 "isEqualNode" 结合使用的方法。 我是否必须编写自己的比较器,或者是否有一种我不知道的方法来确保节点的类型相同?
使用这样的方法的一个问题是它只给出一个布尔值答案,它不会告诉您两个节点之间的实际差异是什么。另一个问题是你无法告诉它你认为重要的差异是什么:例如(据我所知)冗余名称空间声明被这个特定的方法认为是重要的。空格通常是有问题的。我在使用 XPath deep-equal() 方法时遇到了同样的问题,结果写了 saxon:deep-equal 变体。但我现在更喜欢使用一组 XPath 断言来测试预期结果。 W3C XSLT 测试套件将此技术与测试断言一起使用,如下所示:
<result>
<all-of>
<assert>/root/p[1]/text()[1] = 'Tekst '</assert>
<assert>/root/p[1]/text()[2] = ' etc..'</assert>
<assert>/root/p[2]/text()[1] = 'Tekst '</assert>
<assert>/root/p[2]/text()[2] = ' etc..'</assert>
</all-of>
</result>
我曾经有一个小工具可以从 XML 文档中生成这样的断言列表,但现在我倾向于手动执行它们。最大的好处是,如果出现问题,诊断程序会告诉您哪个断言失败了。
您可能会考虑其他三种可能性:
请注意,@Michael Kay 和@JasonPlutext 提供了关于如何测试 XML 一般输出的有趣且更好的替代方案,您可能需要考虑。
至于我的具体问题,即简单地比较两个 XML 节点和 "isEqualNode",一个源于输入字符串,一个源于数据转换,我必须执行以下操作:我可以通过 InputStream 解组它,而不是解析字符串,从而获得所需的节点类型。
// creating the "actual" node I want to test (nothing changed here)
Node xmlNodeActual = XmlUtils.marshaltoW3CDomDocument(actual).getDocumentElement();
//...
// Instead of parsing the string, just unmarshal and marshal it once
Object expected = XmlUtils.unmarshal(new ByteArrayInputStream(strXmlNode.getBytes("utf-8")));
Node xmlNodeExpected = XmlUtils.marshaltoW3CDomDocument(expected).getDocumentElement();
if(!xmlNodeActual.isEqualNode(xmlNodeExpected)) {
// ...
}
这会产生相同的节点类型,并按预期适用于我的设置。不过,这种比较两棵 XML 树的方法有几个缺陷,正如 Michael Kay 所指出的,所以不要认为这是最佳实践,而是求助于另一个答案进行一般 XML 比较。