单元测试......如何改进它

Flo*_*ian 7 c# nunit unit-testing

我想测试一段返回对象的代码.

我使用NUnit并在测试类中编写一个方法来测试我的方法是否正常工作...

[Test]
public void GetMyObjectFromLog()
{
     string _xmlFilePath = @"C:\XmlFile.xml";
     MyObjectParser _myObjectParser = new MyObjectParser();
     MyObject _mockMyObject = new MyObject
                              {
                                   Title = "obj",
                                   Name = "objName"
                              }
     MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath);

     Assert.AreEqual(_mockMyObject , _myObject);
}
Run Code Online (Sandbox Code Playgroud)

此测试不起作用,因为MyObject不覆盖Equals方法,我不想Equals仅为测试目的覆盖方法.

所以我重写了这样的测试:

[Test]
public void GetMyObjectFromLog()
{
     string _xmlFilePath = @"C:\XmlFile.xml";
     MyObjectParser _myObjectParser = new MyObjectParser();
     MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath);

     Assert.AreEqual("obj", _myObject.Title);
     Assert.AreEqual("objName", _myObject.Name);
}
Run Code Online (Sandbox Code Playgroud)

好吧,它有效......但这个测试是否相关?而且,对文件有依赖性.

使用模拟框架而不是相关吗?以及如何使用它?

谢谢 !

Yam*_*vic 5

首先,解析器内部的方法应该是名称"Parse"而不是"Get".

其次,如果你不希望对象本身能够将自己与另一个对象进行比较,那么就像你所做的那样比较它们(属性属性)就完全没问题了.但是这可以在测试类中提取到辅助方法中.

最后,您并不想将解析器与文件紧密耦合.你只想解析文本.如果要包含一个静态帮助器方法,该方法也会打开一个文件和所有内容,这是您的选择,但它不应该是纯实例依赖项.

[Test]
public void ParsesObjectFromXml()
{
     string xmlInput = " ... ";
     MyObjectXmlParser parser = new MyObjectXmlParser();
     MyObject expected = new MyObject() {Title = "obj", Name="objName"};

     AssertMyObjectsAreEqual(expected, parser.Parse(xmlInput));
}

private bool AssertMyObjectsAreEqual(MyObject expected, MyObject actual)
{
     Assert.AreEqual(expected.Title, actual.Title);
     Assert.AreEqual(expected.Name, actual.Name);
}
Run Code Online (Sandbox Code Playgroud)

现在你的班级和考试都更清晰,只有一个责任.


Grr*_*404 1

拥有对文件的引用是绝对可以的。一般有两种测试类型:单元测试和集成测试。

集成测试总是与某些文件/数据库或其他东西交互。在您的情况下,您可以通过模拟 _myObjectParser.GetMyObjectFromLog 来改进测试。

您可以自己编写模拟,也可以使用 rhinomocks 等框架。nunit / rhinomocks 的一本非常好的书是:单元测试的艺术。

GetMyObjectFromLog 的更好的可测试版本可能如下所示:

public MyObject GetMyObjectFromLog(IMyXmlReader reader)
{
    var xmlData = reader.GetData();
    //make your object here
    var obj = new MyObject(xmlData);
    return obj;  
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以实现 2 个新类来实现接口 IMyXmlReader,一个类从文件中读取您的生产代码,另一个类在 GetData() 上始终返回相同的字符串。

然后,您可以使用始终返回静态字符串的类来进行单元测试。

理解?对不起我的英语不好 :)