单元/集成测试中文件系统依赖的最佳实践

21

我刚开始为很多代码编写测试。有一堆类与文件系统有依赖关系,也就是它们读取CSV文件、读/写配置文件等等。

当前测试文件存储在项目的test目录中(这是一个Maven2项目),但由于种种原因,该目录并不总是存在,所以测试会失败。

你知道处理单元/集成测试中文件系统依赖的最佳实践吗?

编辑:我不是要针对上述特定问题寻求答案。那只是一个例子。我更希望得到如何处理对文件系统/数据库等的依赖的一般建议。

5个回答

25

首先,应该尽量避免使用文件系统进行单元测试 - 参考这个单元测试规则集。如果可能,让你的代码在流中工作,这将使得单元测试使用缓冲区(即内存),而生产代码中使用FileStream。

如果无法避免,可以让你的单元测试生成所需的文件。这样做会使测试容易阅读,因为一切都在一个文件中。这也有助于预防权限问题。

你可以在单元测试中模拟文件系统/数据库/网络访问。

对于依赖于数据库或文件系统的单元测试,可以考虑将其视为集成测试。


2

文件系统的依赖有两种类型:

  • 测试所依赖的文件;如果您需要文件来运行测试,则可以在测试中生成它们并将它们放在/tmp目录中。
  • 代码所依赖的文件:配置文件或输入文件。

在第二种情况下,通常可以重新组织代码以消除对文件的依赖(例如,可以使用java.io.InputStreamjava.io.OutputStream替换java.io.File)。当然,这可能不是可能的。

您还可能需要处理文件系统中的“非确定性”(我曾经在NFS上调试过某个魔鬼般的问题)。在这种情况下,您应该在一个薄接口中包装文件系统。

最简单的方法就是编写帮助器方法,这些方法接受一个File并将调用转发到该文件:

InputStream getInputStream(File file) throws IOException {
    return new FileInputStream(file);
}

您可以使用模拟对象来替换此对象,然后可以将其指向抛出异常、返回ByteArrayInputStream或其他操作。

对于URL和URI也是如此。


1

有两种测试需要从文件中读取代码的选项:

  1. 将与单元测试相关的文件保存在源代码控制中(例如在测试数据文件夹中),这样任何获取最新版本并运行测试的人都可以在已知文件夹相对于测试二进制文件的位置上找到相关文件。这可能是“最佳实践”。

  2. 如果涉及的文件很大,您可能不想将它们保存在源代码控制中。在这种情况下,一个网络共享目录,可以从所有开发者和构建机器访问,可能是一个合理的折衷方案。

显然,大多数编写良好的类一开始就不会对文件系统有硬依赖。


0
通常,文件系统测试并不是非常关键的:文件系统已经被很好地理解,易于设置和保持稳定。此外,访问通常相当快速,因此没有理由回避它或嘲笑测试。
我建议您找出目录不存在的原因,并确保它存在。例如,在setUp()中检查文件或目录的存在性,如果检查失败,则复制文件。这只会发生一次,因此性能影响很小。

0

给测试文件(包括输入和输出)命名时,应该与单元测试名称在结构上相似。

例如,在JUnit中,我会使用:

File reportFile = new File("tests/output/" + getClass().getSimpleName() + "/" + getName() + ".report.html");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接