Answers:
就像您在TDD中始终使用外部资源一样:您为文件系统操作创建一个或多个接口,然后“模拟”它们。您想测试“表生成器”和元数据修改代码,而不是文件系统操作本身(很可能您正在使用现成的库实现来访问文件系统)。
拥有“测试”文件系统有什么问题?
创建一个模板文件夹/目录结构,其内容足以测试您的操作。
在设置单元测试期间,请复制此初始结构(建议您将模板压缩并解压缩到测试区域中)。运行测试。拆除期间将整个内容删除。
模拟的问题是,首先,属于您项目的文件系统,操作系统和数据库并没有真正符合外部资源的条件,其次,模拟低级系统调用既费时又容易出错。
这是您绝对需要进行集成测试的事情,因为现实世界中的文件系统具有各种奇怪的行为(例如,Windows不允许在任何程序(包括删除程序)打开的情况下删除文件)。
因此,TDD方法是首先编写集成测试(严格来说,TDD没有“单元测试”和“集成测试”的不同概念;它们只是测试)。这很可能就足够了;这样工作就完成了,停下来,回家。
如果不是这样,将存在一些内部复杂性,很难通过整理文件来进行适当的测试。在这种情况下,您只需消除这种复杂性,将其放入类中,然后为该类编写单元测试。您很可能会发现该通用类在数据库,xml文件等情况下也是可用的。
在任何情况下,您都不会拿出正在编写的代码的基本核心并将其“模拟”出来,以编写可通过的测试,无论被测单元是否错误。
'unit test' and 'integration test'; they are just tests.
我认为现实中,这将是针对我的案例的最佳解决方案-我确实需要测试我用于边缘案例的文件系统库,以及应用程序应如何响应那些。如果我切换到其他文件系统库,则不需要重写大量的模拟/测试代码来使用新库,但是拥有测试文件夹结构和集成测试将使这一过程变得更加简单。
我们将您的问题理解为“一种测试/依赖于文件系统操作的类的良好/可接受的方法”。我不认为您要测试操作系统的文件系统。
为了使“文件系统操作的接口并“模拟它们”的接口”工作尽可能地小,如@Doc Brown回答所建议的那样,请使其尽可能小,最好使用Java 二进制流或文本阅读器(或c#或您正在使用的编程语言),而不是使用文件与文件名,直接在您的TDD开发类。
例:
使用Java我实现了一个类CsvReader
public class CsvReader {
private Reader reader;
public CsvReader(Reader reader) {
this.reader = reader;
}
}
为了测试,我在内存中使用了这样的数据
String contentOfCsv = "TestColumn1;TestColumn2\n"+
"value1;value2\n";
CsvReader sut = new CsvReader(java.io.StringReader(contentOfCsv));
或将测试数据嵌入资源中
CsvReader sut = new CsvReader(getClass().getResourceAsStream("/data.csv"));
在生产中我使用文件系统
CsvReader sut = new CsvReader(new BufferedReader( new FileReader( "/import/Prices.csv" ) ));
这样,我的CsvReader并不依赖于文件系统,而是依赖于存在文件系统实现的抽象“阅读器”。