单元测试. .如何改进它

本文关键字:何改进 单元测试 | 更新日期: 2023-09-27 18:15:19

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

我使用了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);
}

这个测试不工作,因为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);
}

好的,它工作…但这个测试有相关性吗?此外,还存在对文件的依赖关系。

是相关的使用模拟框架而不是?如何使用呢?

单元测试. .如何改进它

首先,解析器中的方法应该命名为"Parse"而不是"Get"。

其次,如果你不希望对象本身能够与另一个对象进行比较,那么就像你所做的那样(逐个属性)比较它们是完全可以的。但这可以提取到测试类中的helper方法中。

最后,您不会真的希望解析器与文件紧密耦合。你只需要解析文本。如果你想包含一个静态助手方法,它也可以打开一个文件,这是你的选择,但它不应该是一个纯粹的实例依赖。

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

现在你的类和测试都更清晰了,只有一个单一的职责。

关于文件的依赖关系(甚至看起来不在项目中!):

你可以覆盖_myObjectParser.GetMyObjectFromLog也接受一个流。然后,您可以将该XML文件添加为嵌入式资源,并从程序集中读取它。

有一个文件的引用是完全可以的。通常有两种测试类型:单元测试和集成测试。

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

您既可以自己编写mock,也可以使用像rhinomocks这样的框架。一本非常适合Unit/rhinommock的书是:The Art of Unit Testing。

GetMyObjectFromLog的一个更好的可测试版本应该是这样的:

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

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

然后,您可以使用始终为单元测试返回静态字符串的Class。

明白吗?抱歉我的英语不好

看起来是这样的。但是,如果您在主项目中不需要Equals,您可以在测试项目中覆盖它。例如,通常我创建的类将私有和受保护的类提升为公共类。因此,您可以自由地扩展您的主要项目,以便在您的测试项目中进行简单的测试。

文件依赖关系是可以的,只需将该文件放在您的测试套件项目中。

单元测试的目的是测试代码的逻辑,你上面的测试做了两件事:1. 逻辑2. 搜索

我说搜索是因为你正在尝试匹配你在外部文件中创建的对象。如果你这样做,问题是你的构建将开始中断,如果没有外部文件存在,你不希望这样。

解决方案:在运行中创建文件,但不要创建物理文件,在内存中创建一个文件,然后插入需要匹配的对象,然后匹配对象。