单元测试 XML 生成

发布于 2024-07-13 05:59:33 字数 1436 浏览 6 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

岁月染过的梦 2024-07-20 05:59:33

首先,正如几乎每个人都在说的那样,验证 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);

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

First, as pretty much everyone is saying, validate the XML if there's a schema defined for it. (If there's not, define one.)

But you can build tests that are a lot more granular than that by executing XPath queries against the document, e.g.:

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

This lets you test not only whether or not your document is semantically valid, but whether or not the method producing it is populating it with the values that you expect.

情深缘浅 2024-07-20 05:59:33

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

它还具有一些有用的 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");

请注意,这是有效的使用 LINQ-To-XML 而不是原始问题中指定的 XmlDocument 对象,但就我个人而言,这些天我发现我使用 LINQ-To-XML 作为首选。

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

Fluent Assertions is an excellent library for expressing test assertions in a fluent, easy to read style. It works with all the major Unit Testing frameworks.

It also has some useful XML functionality (all taken from the examples here), for example:

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

Note that this works with LINQ-To-XML rather than the XmlDocument object specified in the original question but personally these days I find I'm using LINQ-To-XML as a first choice.

It is also quite easily extensible, should you want to add further XML assertions to fit your needs.

千と千尋 2024-07-20 05:59:33

另一种可能性可能是使用 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);
    }

Another possibility might be to use XmlReader and check for an error count > 0. Something like this:

    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);
    }
美胚控场 2024-07-20 05:59:33

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

Validate against XML schema or DTD, also check key that nodes have the values you expect.

浪推晚风 2024-07-20 05:59:33

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

If you have a standard format that you expect the output to be, why not create an XML schema or DTD and validate against that. This won't depend on the data, so will be flexible. Also defining how the XML can be formed can be helpful when designing you system.

后知后觉 2024-07-20 05:59:33

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

您的字符串比较:将会失败,如果手动创建 XML 的一部分而以编程方式创建另一部分,则很容易发生这种情况。

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

因此,如果属性的顺序不同,

Another reason to use a Schema to validate against is that while XML nodes are explicitly ordered, XML attributes are not.

So your string comparison of:

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

would fail if the attributes are in a different order, as could easily happen if one bit of XML was manually created and the other programatically.

音盲 2024-07-20 05:59:33

marianor 的这篇博客文章提供了一种比较 XElement 结构的轻量级方法,因此我将在处理 XMLUnit

要做的第一件事是规范化两个 XML...使用 Linq...两个元素都规范化后,您只需比较两个字符串即可。

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

This blog post by marianor gives a lightweight way to compare XElement structures, so I'm going to try that before tackling XMLUnit.

The first thing to do is normalize the two XMLs...using Linq... After both elements were normalized, simply you can compare both strings.

The XML is normalized by sorting the element and attribute names.

青巷忧颜 2024-07-20 05:59:33

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

Validate it against an XSD schema using XmlSchema class. Its found under System.XML i think.
Another option would be to write a serialization class (XMLSerializer) to deserialize your XML into an object. The gain will be that it will implicitly validate your structure and after that the values can be easily accessed for testing using the resulting object.

梦归所梦 2024-07-20 05:59:33

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

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

  • 错误转义的元素
  • 错误转义的属性
  • 错误转义的元素名称
  • 错误转义的属性名称

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

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

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

使用这种方法,您通常希望立即捕获所有失败,而不是在第一次失败时中止,因此您可能需要巧妙地跟踪发生不匹配的位置。

通过更多的工作,您可以将某些元素类型识别为免于测试(例如时间戳),或者验证它们是否是指向等效节点的指针,或者...您想要的任何类型的自定义验证。

Verify the resulting document is well formed
Verify the resulting document is valid
Verify the resulting document is correct.

Presumably, you are crafting an XML document out of useful data, so you will want to ensure that you have the right coverage of inputs for your tests. The most common problems I see are

  • Incorrectly escaped elements
  • Incorrectly escaped attributes
  • Incorrectly escaped element names
  • Incorrectly escaped attribute names

So if you haven't already done so, you would need to review the XML spec to see what's allowed in each place.

How much "checking" should happen in each test isn't immediately clear. It will depend a lot on what a unit is in your problem space, I suppose. It seems reasonable that each unit test is checking that one piece of data is correctly expressed in the XML. In this case, I'm in agreement with Robert that a simple check that you find the right data at a single XPath location is best.

For larger automated tests, where you want to check the entire document, what I've found to be effective is to have an Expected results which is also a document, and walk through it node by node, using XPath expressions to find the corresponding node in the actual document, and then applying the correct comparison of the data encoded in the two nodes.

With this approach, you'll normally want to catch all failures at once, rather than aborting on first failure, so you may need to be tricksy about how you track where mismatches occurred.

With a bit more work, you can recognize certain element types as being excused from a test (like a time stamp), or to validate that they are pointers to equivalent nodes, or... whatever sort of custom verification you want.

燃情 2024-07-20 05:59:33

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

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

I plan on using this new Approval Testing library to help with XML testing.

It looks to be perfect for the job, but read it first yourself as I don't have experience using it.

酒中人 2024-07-20 05:59:33

为什么不假设某些商业 xml 解析器是正确的并根据它验证您的 xml 代码呢? 就像是。

Assert.IsTrue(myDoc.Xml.ParseOK)

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

why not assume that some commercial xml parser is correct and validate your xml code against it? something like.

Assert.IsTrue(myDoc.Xml.ParseOK)

other than that and if you want to be thorough I'd say you would have to build a parser yourself and validate each rule the xml specification requires.

開玄 2024-07-20 05:59:33

您可以使用 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 属性或类似属性)。 这可以通过使用 DifferenceListener 来解决断言生成的 xml。

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

You can use a DTD to check for the validity of the generated xml.

To test for the correct content I would go for XMLUnit.

Asserting xml using XMLUnit:

XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);

Diff diff = new Diff(expectedDocument, obtainedDocument);
XMLAssert.assertXMLIdentical("xml invalid", diff, true);

One thing you might come across is the fact that the generated xml might contain changing identifiers (id/uid attributes or alike). This can be solved by using a DifferenceListener when asserting the generated xml.

Example implementation of such 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
    }
}

using 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文