【问题标题】:Using TDD to develop file traversing code in Java使用TDD开发Java文件遍历代码
【发布时间】:2014-07-04 03:02:09
【问题描述】:

我必须实现一些代码来遍历目录结构并返回找到的文件列表。要求很简单:

  1. 给定一个基目录,找到其中的所有文件(它们本身不是目录)。
  2. 如果找到目录,请对其重复步骤 1。

我想使用 TDD 开发代码。当我开始编写测试时,我意识到我在模拟类File,所以我可以拦截对File.isDirectory() 的调用等等。通过这种方式,我强迫自己使用一个我会调用该方法的解决方案。

我不喜欢它,因为这个测试肯定与实现紧密耦合。如果我改变了询问文件是否为目录的方式,那么即使我保持合同工作,这个测试也会失败。由于该帖子中表达的所有原因,将其视为Private Unit Test 让我感到不安。我不确定这是否是我需要使用这种测试的情况之一。另一方面,我真的很想确保它返回每个文件,而不是目录,遍历整个结构。对我来说,这需要一个好的、简单的测试。

我想避免必须在“磁盘上”创建包含真实测试文件的测试目录结构,因为我认为它相当笨拙并且违背了我读过的一些最佳实践。

请记住,我不需要对内容做任何事情,因此使用 StringReader 而不是 FileReader 之类的技巧在这里不适用。不过,我认为我可以做一些等效的事情,比如当我设置测试时能够在内存中创建一个目录结构,然后将其拆除。我还没有找到方法。

您将如何使用 TDD 开发此代码?

谢谢!

【问题讨论】:

  • 一个选项是Commons VFS,但通常我只使用“真实”文件访问,并让我的测试使用特殊目录进行测试。
  • @DavidWallace 你应该把它作为答案。
  • 谢谢@DavidWallace!我想 Commons VFS 对我的目的来说可能是一种矫枉过正。拥有一个“真实的”文件结构可以简化测试并使其与实现的耦合度大大降低。我试试看!
  • 是的,我发现使用真实文件效果很好。虽然有一些陷阱。你真的想给每个测试方法自己的子目录,以消除测试相互交互的可能性。并确保测试在运行之前和之后都清理了自己的目录,以防万一它在之前的测试运行中途终止,并留下一些不需要的文件。

标签: java unit-testing junit tdd


【解决方案1】:

你犯的错误是模拟File。有一个测试反模式假设如果你的班级委托给班级X,你必须模拟班级X来测试你的班级。还有一个一般规则是在编写执行文件 I/O 的单元测试时要谨慎,因为它们往往太慢。但在单元测试中并没有绝对禁止文件 I/O。

在您的单元测试中设置并拆除一个临时目录,并在该临时目录中创建测试文件和目录。是的,您的测试会比纯 CPU 测试慢,但它们仍然会很快。 JUnit 甚至有支持代码来帮助解决这种情况:@Rule 上的 TemporaryFolder

就在这周,我使用 TDD 实现了一些必须扫描目录并删除文件的内务管理代码,所以我知道这是可行的。

【讨论】:

    【解决方案2】:

    作为一个对需要超过几毫秒才能完成的单元测试感到非常不安的人,我强烈建议模拟文件 I/O。

    但是,我认为您不应该直接模拟File 类。相反,请将您对File 类的使用视为“如何”,并尝试识别“什么”。然后codify that with an interface

    例如:您提到您所做的其中一件事是拦截对File.isDirectory 的调用。如果您的代码与某个接口的实现进行交互,而不是与 File 类进行交互,例如:

    public interface FileSystemNavigator {
        public boolean isDirectory(String path);
    
        // ... other relevant methods
    }
    

    这会将File.isDirectory 的使用从您的其余代码中隐藏起来,同时将reframing the problem 隐藏在与您的程序更相关的内容中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 2016-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多