如何对具体的依赖项进行单元测试

本文关键字:单元测试 依赖 | 更新日期: 2023-09-27 18:03:36

我有一个业务层类,它使用System.IO.File从各种文件中读取信息。为了对这个类进行单元测试,我选择用注入的依赖项替换File类上的依赖项,如下所示:

using System.IO;
public interface IFileWrapper
{
    bool FileExists( string pathToFile );
    Stream Open( string pathToFile );
}

现在我可以使用Mock测试我的类,一切正常。另外,我需要一个具体的实现。我有以下内容:

using System;
using System.IO;
public class FileWrapper : IFileWrapper
{
    public bool FileExists( string pathToFile )
    {
        return File.Exists( pathToFile );
    }
    public Stream Open( string pathToFile )
    {
        return File.Open( pathToFile, FileMode.Open, FileAccess.Read, FileShare.Read );
    }
}

现在我的业务类不再依赖于System.IO.File类,可以使用IFileWrapper的Mock进行测试。我认为没有必要测试System.IO.File类,因为我认为微软已经对它进行了彻底的测试,并在无数次使用中得到了证明。

我如何测试具体的FileWrapper类?虽然这是一个简单的类(低风险),但我有更大的示例,它们遵循相同的方法。如果不完成这些,我就无法达到100%的代码覆盖率(假设这很重要)。

我想这里更大的问题是,如何弥合单元测试和集成测试之间的差距?是否有必要测试这个类,或者是否有一些属性来修饰这个类,以便将其从代码覆盖率计算中排除。

如何对具体的依赖项进行单元测试

根据经验,您应该对编写的所有产品代码进行单元测试。然而,由于。net设计的本质,总是会有像上面的Adapter类这样的类无法进行适当的单元测试。

我个人的经验法则是,如果你能将适配器中的每个成员减少到圈复杂度为1,那么就可以将其声明为Humble Object。

我敢说没有办法从覆盖率报告中排除代码,但是你可以在独立的程序集中实现你的Humble Objects,这些程序集不受覆盖率报告的影响。

在您的情况下,测试FileWrapper是一个开销。它除了作为包装器之外没有任何作用。因此,我将使用将其排除在覆盖率计算之外的属性。

在其他情况下,您可以在诸如FileWrapper之类的类型中添加一些额外的逻辑,在这些情况下,集成测试可以帮助您。

我想这里更大的问题是,如何弥合两者之间的差距单元测试和集成测试?

一般来说,您应该分别使用这两种测试。集成测试应该在更高的层次上,测试两个组件之间的集成,所以如果你觉得你需要测试这个依赖关系——继续,在其他情况下不要写这样的测试。集成测试总是比单元测试更复杂,运行时间更长,维护起来也更困难,所以在编写每个集成测试之前都应该三思。这就是为什么我不会说,如果你要为FileWrapper写一些测试,这将是一个集成测试。所以我的观点是单元测试和集成测试之间没有差距,它们解决的是不同的问题。

适配器类的唯一目的是包装文件系统。因此,您可以做一个单元测试来检查这种行为是否正确。对包装器工作正确感到满意之后,您就可以在其他地方轻松地使用test double了。

您的单元测试应该非常简单,但必须使用具体的实现。这意味着它可能会相对较慢(> 5ms),并且在设置/拆除时有些烦人。我对单元测试的定义是运行相对较快并且测试少量代码的测试,在这种情况下,测试一个类。

您必须非常小心,不要在类中添加任何额外的逻辑,否则该逻辑也将需要进行困难的单元测试。

第二种方法是在集成测试或手动测试中覆盖它。如果在任何地方都使用这个类,您将很快捕获任何错误。由于该类的复杂性很小,因此引入错误的风险很低。