如何对xml文件进行单元测试?

时间:2014-01-31 09:44:58

标签: c# xml unit-testing

我已经为以下xml文件提供了XSD架构

<?xml version="1.0"?>
<note>
 <to> </to>
 <from> </from>
 <datetime>  </datetime>
 <heading> </heading>
 <body> </body>
</note>

我实现了一个NoteGnerator来根据模式生成xml文件。必须针对某些模板/规范生成xml文件,例如:

<?xml version="1.0"?>
<note>
 <to> Lucy </to>
 <from> Lily </from>
 <datetime> --date--time-- </datetime>
 <heading> reminder </heading>
 <body> do not forget my pen </body>
</note>

另一个模板/规范如下:

<?xml version="1.0"?>
<note>
 <to> Lily </to>
 <from> Lucy </from>
 <datetime> --date--time-- </datetime>
 <heading> reply </heading>
 <body> no problem </body>
</note>

,其中<datetime>是生成xml时的动态值(因此无法预先确定此值)。基于XSD方案和这两个XML规范,我可以轻松生成XML消息。

如何对生成的XML文件进行单元测试?

我是否需要再次验证生成的XML文件?或者我需要使用一些diff工具来比较生成的xml文件和模板?因为日期时间是动态的,所以每次生成xml文件时它都不同,那么如何将它们与模板进行比较呢?或者我需要将xml反序列化为c#对象,然后测试c#对象?

2 个答案:

答案 0 :(得分:2)

这可能对您有所帮助。在这里,我创建一个对象,分配值,将其写入XML,读取XML,并将其与原始对象进行比较。我假设你有全班结构。

// This is your expected object which you are going to write to xml.
var sourceObject = new SomeClassToWriteInXML();

// Writing object to XML.
var document = new XDocument();
var serializer = new XMLSerializer(typeof(SomeClassToWriteInXML));
using (var writer = document .CreateWriter())
{
    serializer.Serialize(writer, source);
}
// write document to a file.

// Now document has the XML document.
// Need to read file you have just created. For testing sake I am reading document.
var actual = new SomeClassToWriteInXML();
// Deserialize xml to get actual object (which should be equal to sourceObject)
using (var reader = document.CreateReader())
{
    actual = (SomeClassToWriteInXML)serializer.Deserialize(reader);
}

Assert.AreEqual(expected.First(), actual.First());

答案 1 :(得分:1)

除了datetime之外,您可以轻松地比较生成的XML节点值。这是因为它具有非确定性。在单元测试(和代码设计)中,这些问题通常以两种方式解决:

  • 完全消除非决定论
  • 放宽与非确定性相关的要求(例如,通过不执行精确匹配,而是某种模糊/近似匹配)

使用第一个解决方案,您的笔记生成组件需要将当前日期时间抽象为外部服务/依赖项,例如:

public class NoteGenerator
{
    private readonly ICurrentDateProvider currentDateProvider;
    public NoteGenerator(ICurrentDateProvider )currentDateProvider
    {
        this.currentDateProvider = currentDateProvider;
    }

    public string GenerateNote()
    {
        var currentDate = currentDateProvider.Now;
        // ...

现在在单元测试中,您可以使用您选择的隔离框架伪造该依赖关系并对您自己设置的确定性值执行断言(例如FakeItEasy):

var dateProvider = A.Fake<ICurrentDateProvider>();
A.CallTo(() => dateProvider.Now).Returns(new DateTime(2014, 01, 31, 10, 30));
var generator = new NoteGenerator(dateProvider);

// ...

第二种方法是替换日期时间必须是此值 - 匹配日期时间不得早于 - 匹配,例如:

var oneMinuteAgo = DateTime.Now.AddMinutes(-1.0);
var generator = new NoteGenerator();

var dateFromXml = // extract 
Assert.That(dateFromXml, Is.GreaterThan(oneMinuteAgo));