使用文件IO的unit testing方法

我正在努力养成编写unit testing的习惯,我之前写过一些,但它们通常都很基础……我想开始转向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抽象层,但这听起来像是它可能会不必要地使代码复杂化……

这样的项目值得unit testing吗? 我的意思是,这太简单了。 一旦你剥离.Net和第三方库调用就没有多少了……那么,使其可测试的工作量意味着它不是一个很好的测试候选者吗?

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

干杯

关于如何测试文件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); } 

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

这有点工作要做,但是你也不需要测试文件I / O.

最佳Jan

如何使用IO测试方法?

通过在.NET的IO库中引入抽象,然后在应用程序中使用实际实现(BCL),在unit testing中使用伪(模拟)。 这种抽象在你自己编写时相当简单,但是那些项目已经存在(例如System.IO.Abstraction ),所以重新发明轮子毫无意义,特别是在如此微不足道的事情中。

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

这是正确的,在测试中你想使用模拟 )对象 。

这样的项目值得unit testing吗?

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

请注意,手动测试复杂解析器方法的10个边缘情况几乎总是耗费时间,每次都需要加载大文件并等待结果。 这是隔离环境中的自动化测试有用的地方。 它与您的代码相同 – 文件系统,Web服务,它们都会在您获得实际业务逻辑之前引入大量开销。 必须孤立。

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

再次纠正,你应该测试公共合同。 但是,如果私有东西变得足够大,可以测试它,大多数时候它是一个很好的指标,它也足够大,可以把它放在自己的类中。 请注意,仅为unit testing使用更改成员访问修饰符不是最好的主意。 提取类/方法重构几乎总是更好。

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

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

     var mock = new Mock>(); 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属性来避免可见性问题。

    外部可见的测试方法

我认为这是关于企业编程的。 用您自己的可靠代码来节省时间。

希望我的观点可以帮到你。

你可以使用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 }