文件IO的单元测试方法

本文关键字:测试方法 单元 IO 文件 | 更新日期: 2023-09-27 18:13:21

我正在努力养成写单元测试的习惯,我以前写过一些,但它们通常都是非常基本的…我想开始转向TDD,因为我想提高我的代码质量(设计和结构)——减少耦合,同时希望减少溜进可测试构建的回归数量。

我开始做一个相对简单的项目。生成的程序监视一个文件夹,然后对该文件夹中的文件进行操作。

下面是从项目中提取的一些典型代码示例:

private string RestoreExtension(String file)
    {
        var unknownFile = Path.GetFileName(file);
        var ignoreDir = Path.GetDirectoryName(file) + "''Unknown";
        string newFile;
        //We need this library for determining mime
        if (CheckLibrary("urlmon.dll"))
        {
            AddLogLine("Attempting to restore file extension");
            var mime = GetMimeType(BufferFile(file, 256));
            var extension = FileExtensions.FindExtension(mime);
            if (!String.IsNullOrEmpty(extension))
            {
                AddLogLine("Found extension: " + extension);
                newFile = file + "." + extension;
                File.Move(file, newFile);
                return newFile;
            }
        }
        else
        {
            AddLogLine("Unable to load urlmon.dll");
        }
        AddLogLine("Unable to restore file extension");
        if (!Directory.Exists(ignoreDir))
        {
            Directory.CreateDirectory(ignoreDir);
        }
        var time = DateTime.Now;
        const string format = "dd-MM-yyyy HH-mm-ss";
        newFile = ignoreDir + "''" + unknownFile + "-" + time.ToString(format);
        File.Move(file, newFile);
        return String.Empty;
    }

问题:

如何使用IO测试方法?我真的不想使用一个真正的文件,因为这将是缓慢的(和更多的集成测试?),但我真的看不到其他方法。我可以添加一个可切换的IO抽象层,但这听起来可能会不必要地使代码复杂化……

这样的项目值得进行单元测试吗?我的意思是,是不是太简单了。一旦你去掉。net和第三方库调用,剩下的就不多了……那么,使其可测试的工作量是否意味着它不是一个好的测试候选?

这个项目中的很多方法都是私有的,因为这个项目恰好是一个windows服务。我读过你应该只测试外部可见的方法(公共或通过接口暴露),但在这种情况下,我不太可能公开我自己的任何方法。那么这个项目是否值得测试(因为我可能需要将方法访问修饰符更改为public或添加一些属性以便NUnit可以看到它们)?

文件IO的单元测试方法

关于如何测试文件I/O:一种常见的方法是将文件I/O封装在包装器类中。例如:
public class FileHandler : IFileHandler
{
     public string GetFilename(string name)
     {
         return System.IO.GetFileName(name);
     }
    public string GetDirectoryName(string directory)
    {
         return System.IO.GetDirectoryName(directory);
    }
}
public interface IFileHandler
{
      string GetFilename(string name);
      string GetDirectoryName(string directory);
}

在测试中的方法中,您只针对接口进行编程。当您运行单元测试时,您将使用返回预定义值的模拟对象。为此,您可以使用Moq。

这是一点工作要做,但你不需要测试文件I/O。

最好1月

如何使用IO测试方法?

通过在。net的IO库上引入抽象,然后在应用程序中使用真实实现(BCL),在单元测试中使用假实现(mock)。这样的抽象是相当简单的编写自己,但这些项目已经存在(例如。所以重新发明轮子是没有意义的,尤其是在这种琐碎的事情上。

我真的不想使用一个真正的文件,因为这会很慢

这是正确的,在测试中你想使用fake (mock)对象。

这样的项目值得进行单元测试吗?

每个项目都值得测试,你将以一种或另一种方式测试它(在最极端的情况下,通过手动执行应用程序并进行良好的老式点击等待测试)。

请注意,手动测试复杂解析器方法的10个边缘情况几乎总是太耗时,每次都需要加载大文件并等待结果。这就是隔离环境中的自动化测试能提供很大帮助的地方。你的代码文件系统、web服务也是一样,它们在你进入实际的业务逻辑之前都会引入大量的开销。必须隔离。

这个项目中的很多方法都是私有的(…)我读过你应该只测试外部可见的方法

正确,你应该测试公共合同。然而,如果私有的东西变得足够大,可以对它进行测试,大多数情况下,这是一个很好的指标,它也足够大,可以把它放在自己的类中。请注意,仅为单元测试使用更改成员访问修饰符并不是最好的主意。几乎总是提取类/方法重构更好。

你可以使用Microsoft Fakes。首先为System.dll或任何其他包生成一个假程序集,然后模拟预期的返回,如:

using Microsoft.QualityTools.Testing.Fakes;
...
using (ShimsContext.Create())
{
     System.IO.Fakes.ShimDirectory.ExistsString = (p) => true;
     System.IO.Fakes.ShimFile.MoveStringString = (p,n) => {};
     // .. and other methods you'd like to test
     var result = RestoreExtension("C:'myfile.ext");
     // then you can assert with this result 
}

我对TDD也很陌生,但我想我可以给你一些建议:

  1. 关于IO测试。您可以使用模拟对象。为要测试的方法创建一个模拟,并将其与实际传递的值进行比较。在Moq框架中,它看起来像这样:

    var mock = new Mock<IRepository<PersonalCabinetAccount>>();
    mock.Setup(m => m.RemoveByID(expectedID))
        .Callback((Int32 a) => Assert.AreEqual(expectedID, a));
    var account = new PersonalCabinetAccount {ID = myID};
    var repository = mock.Object;
    repository.RemoveByID(account.myId);
    
  2. 绝对是的。如果你想养成一种习惯,我想你需要测试一切。

  3. 你可以使用InternalsVisibleTo属性来避免可见性问题。

    外部可见的测试方法

我认为这是关于企业编程的。只需要花点时间在你自己的可信代码上。

希望我的观点对你有帮助。