用TDD开发Java文件遍历代码
我必须实现一些代码来遍历目录结构并返回找到的文件列表。要求非常简单:用TDD开发Java文件遍历代码,java,unit-testing,junit,tdd,Java,Unit Testing,Junit,Tdd,我必须实现一些代码来遍历目录结构并返回找到的文件列表。要求非常简单: 给定一个基本目录,查找其中的所有文件(不是目录本身) 如果找到目录,请对其重复步骤1 我想用TDD开发代码。当我开始编写测试时,我意识到我在模拟classFile,因此我可以拦截对File.isDirectory()等的调用。通过这种方式,我强迫自己使用一种我将调用该方法的解决方案 我不喜欢它,因为这个测试肯定与实现紧密耦合。如果我改变了询问文件是否是目录的方式,那么即使我保持契约工作,这个测试也会失败。把它当作一个例子让我感
File
,因此我可以拦截对File.isDirectory()
等的调用。通过这种方式,我强迫自己使用一种我将调用该方法的解决方案
我不喜欢它,因为这个测试肯定与实现紧密耦合。如果我改变了询问文件是否是目录的方式,那么即使我保持契约工作,这个测试也会失败。把它当作一个例子让我感到不安,因为在那篇文章中表达了所有的理由。我不确定这是否是我需要使用这种测试的情况之一。另一方面,我真的想确保它返回的每个文件都不是一个目录,遍历整个结构。对我来说,这需要一个好的、简单的测试
我希望避免创建一个带有“磁盘上”真实测试文件的测试目录结构,因为我认为它相当笨拙,而且与我读过的一些最佳实践背道而驰
请记住,我不需要对内容执行任何操作,因此使用StringReader
而不是FileReader
之类的技巧在这里不适用。不过,我认为我可以做一些类似的事情,比如在设置测试时能够在内存中创建目录结构,然后将其拆下。我还没找到办法
您将如何使用TDD开发此代码
谢谢 对于需要超过几毫秒才能完成的单元测试,我非常不安,因此强烈建议模拟文件I/O 但是,我认为您不应该直接模拟
文件
类。相反,请将文件类的使用视为“如何”,并尝试识别“什么”。那么
例如:您提到您要做的一件事是拦截对File.isDirectory
的调用。与其与文件
类交互,不如让代码与接口的某些实现交互,如:
public interface FileSystemNavigator {
public boolean isDirectory(String path);
// ... other relevant methods
}
这会将文件.isDirectory的使用隐藏在代码的其余部分,同时隐藏在与程序更相关的部分。您犯的错误是模拟文件。有一种测试反模式假设如果您的类委托给类X
,您必须模拟类X
,才能测试您的类。还有一条一般规则,就是在编写进行文件I/O的单元测试时要谨慎,因为它们往往太慢。但在单元测试中并没有绝对禁止文件I/O
在单元测试中,设置并拆除临时目录,并在该临时目录中创建测试文件和目录。是的,您的测试将比纯CPU测试慢,但它们仍然很快。JUnit甚至有支持代码来帮助实现这个场景:一个临时文件夹上的@Rule
就在本周,我使用TDD实现了一些内务代码,这些代码必须扫描目录并删除文件,所以我知道这是可行的。一个选项是,但通常我只使用“真实”文件访问,让我的测试使用一个特殊的目录进行测试。@DavidWallace你应该把它作为一个答案。谢谢@DavidWallace!我想Commons VFS对我来说可能是一种过度的杀伤力。拥有一个“真实”的文件结构简化了测试,并使其与实现的耦合性大大降低。我试试看!是的,我发现使用真实文件效果很好。不过也有一些问题。您确实希望为每个测试方法提供自己的子目录,以消除测试相互交互的可能性。并确保测试在运行之前和之后都会清理自己的目录,以防它在上一次运行测试时中途终止,并留下一些不需要的文件。