【问题标题】:Unit testing XML Generation [closed]单元测试 XML 生成 [关闭]
【发布时间】:2010-10-04 23:08:26
【问题描述】:

人们推荐的用于测试 xml 的单元测试策略是正确生成的。

我目前的测试看起来有点原始,类似于:

[Test]
public void pseudo_test()
{
   XmlDocument myDOC = new XmlDocument();
   mydoc = _task.MyMethodToMakeXMLDoc();

   Assert.AreEqual(myDoc.OuterXML(),"big string of XML")
}

【问题讨论】:

    标签: c# xml unit-testing nunit


    【解决方案1】:

    为什么不假设某些商业 xml 解析器是正确的并针对它验证您的 xml 代码呢?类似的东西。

    Assert.IsTrue(myDoc.Xml.ParseOK)
    

    除此之外,如果您想要彻底,我会说您必须自己构建解析器并验证 xml 规范所需的每条规则。

    【讨论】:

      【解决方案2】:

      另一种可能是使用 XmlReader 并检查错误计数 > 0。像这样:

          void CheckXml()
          {
              string _xmlFile = "this.xml";
              string _xsdFile = "schema.xsd"; 
              StringCollection _xmlErrors = new StringCollection();
      
              XmlReader reader = null;
              XmlReaderSettings settings = new XmlReaderSettings();
              settings.ValidationEventHandler += new ValidationEventHandler(this.ValidationEventHandler);
              settings.ValidationType = ValidationType.Schema;
              settings.IgnoreComments = chkIgnoreComments.Checked;
              settings.IgnoreProcessingInstructions = chkIgnoreProcessingInstructions.Checked;
              settings.IgnoreWhitespace = chkIgnoreWhiteSpace.Checked;
              settings.Schemas.Add(null, XmlReader.Create(_xsdFile));
              reader = XmlReader.Create(_xmlFile, settings);
              while (reader.Read())
              {
              }
              reader.Close();
              Assert.AreEqual(_xmlErrors.Count,0);
          }    
      
          void ValidationEventHandler(object sender, ValidationEventArgs args)
          {
              _xmlErrors.Add("<" + args.Severity + "> " + args.Message);
          }
      

      【讨论】:

      • XMLUnit 已经会比较 xml 文件并根据需要计算差异的数量...
      【解决方案3】:

      如果您有一个您期望输出的标准格式,为什么不创建一个 XML 模式或 DTD 并根据它进行验证。这将不依赖于数据,因此将是灵活的。在设计系统时,定义 XML 的形成方式也很有帮助。

      【讨论】:

        【解决方案4】:

        根据 XML 模式或 DTD 进行验证,同时检查节点是否具有您期望的值。

        【讨论】:

        • +1,C# 的 XmlSerialization 可以帮助解决这个问题。
        【解决方案5】:

        XMLUnit 可以帮到你。

        【讨论】:

          【解决方案6】:

          使用 XmlSchema 类针对 XSD 架构对其进行验证。我认为它是在 System.XML 下找到的。 另一种选择是编写一个序列化类 (XMLSerializer) 将您的 XML 反序列化为一个对象。收益将是它将隐式验证您的结构,然后可以轻松访问这些值以使用结果对象进行测试。

          【讨论】:

          • 有更好的验证方法使用 XMLUnit ...
          【解决方案7】:

          首先,几乎每个人都在说,验证 XML 是否定义了模式。 (如果没有,定义一个。)

          但是您可以通过对文档执行 XPath 查询来构建更精细的测试,例如:

          string xml="Your xml string here" ;
          XmlDocument doc = new XmlDocument();
          doc.LoadXml(xml);
          path = "/doc/element1[@id='key1']/element2[. = 'value2']";
          Assert.IsTrue(doc.SelectSingleNode(path) != null);
          

          这不仅可以让您测试您的文档在语义上是否有效,还可以测试生成它的方法是否使用您期望的值填充它。

          【讨论】:

            【解决方案8】:

            使用 Schema 进行验证的另一个原因是,虽然 XML 节点是明确排序的,但 XML 属性不是。

            所以你的字符串比较:

            Assert.AreEqual(myDoc.OuterXML(),"big string of XML")
            

            如果属性的顺序不同,则会失败,如果手动创建一个 XML 位而另一个以编程方式创建,则很容易发生这种情况。

            【讨论】:

              【解决方案9】:

              验证生成的文档格式正确 验证生成的文档是否有效 验证生成的文档是否正确。

              假设您正在使用有用的数据制作 XML 文档,因此您需要确保您的测试输入正确覆盖。我看到的最常见的问题是

              • 元素转义错误
              • 转义属性不正确
              • 元素名称转义错误
              • 属性名称转义错误

              因此,如果您还没有这样做,则需要查看 XML 规范以了解每个地方允许的内容。

              每个测试应该进行多少“检查”尚不清楚。我想,这在很大程度上取决于您的问题空间中的单元。每个单元测试都检查一条数据是否在 XML 中正确表达,这似乎是合理的。在这种情况下,我同意 Robert 的观点,即最好简单检查一下您是否在单个 XPath 位置找到了正确的数据。

              对于要检查整个文档的大型自动化测试,我发现有效的方法是拥有一个预期结果,它也是一个文档,然后逐个节点地遍历它,使用 XPath 表达式来查找实际文档中对应的节点,然后应用两个节点中编码的数据的正确比较。

              使用这种方法,您通常希望一次捕获所有故障,而不是在第一次故障时中止,因此您可能需要小心处理不匹配发生的位置。

              通过更多的工作,您可以识别出某些元素类型被排除在测试之外(如时间戳),或者验证它们是指向等效节点的指针,或者......您想要的任何类型的自定义验证.

              【讨论】:

                【解决方案10】:

                marianor 的This blog post 提供了一种比较 XElement 结构的轻量级方法,因此我将在处理 XMLUnit 之前尝试一下。

                首先要做的是规范化两个 XMLs...使用 Linq...在两个元素都被规范化之后,您可以简单地比较两个字符串。

                通过对元素和属性名称进行排序来规范化 XML。

                【讨论】:

                  【解决方案11】:

                  我计划使用这个新的Approval Testing 库来帮助进行 XML 测试。

                  它看起来非常适合这项工作,但请先自己阅读,因为我没有使用它的经验。

                  【讨论】:

                    【解决方案12】:

                    Fluent Assertions 是一个出色的库,用于以流畅、易读的风格表达测试断言。它适用于所有主要的单元测试框架。

                    它还具有一些有用的 XML 功能(均取自示例 here),例如:

                    xElementA.Should().Be(xElementB);
                    
                    xDocument.Should().HaveRoot("configuration");
                    xDocument.Should().HaveElement("settings");
                    
                    xElement.Should().HaveAttribute("age", "36");
                    xElement.Should().HaveElement("address");
                    
                    xAttribute.Should().HaveValue("Amsterdam");
                    

                    请注意,这适用于 LINQ-To-XML 而不是原始问题中指定的 XmlDocument 对象,但我个人最近发现我使用 LINQ-To-XML 作为首选。

                    如果您想添加更多 XML 断言以满足您的需要,它也很容易扩展。

                    【讨论】:

                    • 新链接here
                    • @BenGulapa 谢谢,用新链接更新答案。
                    • documentation的新链接
                    【解决方案13】:

                    您可以使用 DTD 检查生成的 xml 的有效性。

                    为了测试正确的内容,我会选择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
                        }
                    }
                    

                    使用差异监听器:

                        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);
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-01-03
                      • 2011-05-15
                      • 1970-01-01
                      • 2010-09-10
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多