C# 单元测试XML生成

C# 单元测试XML生成,c#,xml,unit-testing,nunit,C#,Xml,Unit Testing,Nunit,人们推荐什么样的单元测试策略来正确生成xml 我目前的测试似乎有点原始,大致如下: [Test] public void pseudo_test() { XmlDocument myDOC = new XmlDocument(); mydoc = _task.MyMethodToMakeXMLDoc(); Assert.AreEqual(myDoc.OuterXML(),"big string of XML") } 为什么不假设某个商业xml解析器是正确的,并根据它验证xm

人们推荐什么样的单元测试策略来正确生成xml

我目前的测试似乎有点原始,大致如下:

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

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

为什么不假设某个商业xml解析器是正确的,并根据它验证xml代码?差不多

Assert.IsTrue(myDoc.Xml.ParseOK)

除此之外,如果您想彻底了解,我认为您必须自己构建一个解析器,并验证xml规范要求的每个规则。

另一种可能是使用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);
    }
void CheckXml()
{
字符串_xmlFile=“this.xml”;
字符串_xsdFile=“schema.xsd”;
StringCollection_xmlErrors=新建StringCollection();
XmlReader=null;
XmlReaderSettings设置=新建XmlReaderSettings();
settings.ValidationEventHandler+=新的ValidationEventHandler(this.ValidationEventHandler);
settings.ValidationType=ValidationType.Schema;
settings.IgnoreComments=chkignorecommons.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(对象发送方,validationEventTargs参数)
{
_添加(“+args.Message”);
}

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

根据XML模式或DTD进行验证,还要检查节点是否具有所需的值

可能会帮助您。

使用XmlSchema类根据XSD模式验证它。我想它可以在System.XML下找到。
另一种选择是编写序列化类(XMLSerializer),将XML反序列化为对象。这样做的好处是,它将隐式地验证您的结构,然后可以使用结果对象轻松访问这些值进行测试

首先,正如几乎所有人都说的,如果有为XML定义的模式,请验证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);

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

使用模式进行验证的另一个原因是,虽然XML节点是显式排序的,但XML属性不是

因此,您的字符串比较:

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

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

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

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

  • 错误转义的元素
  • 错误转义的属性
  • 错误转义的元素名称
  • 错误转义的属性名称
因此,如果您还没有这样做,那么您需要查看XML规范,看看每个地方都允许什么

在每次测试中应该进行多少“检查”目前还不清楚。我想,这在很大程度上取决于你的问题空间中有什么单位。似乎每个单元测试都在检查XML中是否正确表达了一段数据是合理的。在本例中,我同意Robert的观点,即在单个XPath位置进行一次简单的检查,确保找到正确的数据是最好的

对于更大的自动化测试,您希望检查整个文档,我发现有效的方法是获得预期的结果,这也是一个文档,并使用XPath表达式逐节点遍历它,以在实际文档中找到相应的节点,然后对两个节点中编码的数据进行正确的比较

使用这种方法,您通常希望一次捕获所有失败,而不是在第一次失败时中止,因此您可能需要对如何跟踪不匹配发生的位置保持谨慎

通过进一步的工作,您可以将某些元素类型识别为已从测试中免除(如时间戳),或者验证它们是否是指向等效节点的指针,或者。。。不管你想要什么样的自定义验证。

marianor提供了一种比较XElement结构的轻量级方法,所以我将在解决之前尝试一下

首先要做的是规范化这两个XML…使用Linq。。。两个元素规范化后,只需比较两个字符串即可

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

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

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

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

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

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");
请注意,这适用于LINQtoXML,而不是原始问题中指定的XmlDocument对象,但就我个人而言,这些天我发现我使用LINQtoXML作为第一选择

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

您可以使用DTD
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);

Diff diff = new Diff(expectedDocument, obtainedDocument);
XMLAssert.assertXMLIdentical("xml invalid", diff, true);
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);