在基于TDD的单元测试中处理I / O

时间:2018-09-08 05:57:34

标签: java unit-testing io tdd

我正在练习基于Java的TDD,并编写一些代码来读写文件。现在,对于每种情况(读写),我都有大约100个测试来测试我的代码,在这里我每次都创建一个文件或读取一个给定的文件。要写入的文件将在临时目录中创建,并且在每次测试运行后都会被删除。 但是这种策略会产生大量的I / O,例如SSD寿命。不能选择模拟。

一种可能性是读取/写入一次文件,然后针对(静态)数据结构(伪代码)运行我的测试:

private static Object resultData = null;

@BeforeClass
// Read/Write my stuff here
resultData = ....

@Test
// Check my requirements
assertTrue(resultData....);

问题是,我可以在测试方法内更改预期的行为,因此我的测试不再是自治的。

您将如何处理?

2 个答案:

答案 0 :(得分:2)

  

但是这种策略会产生大量的I / O,例如   SSD使用寿命。

您对此有所考虑:SSD Disk(今天已经足够标准)的DWPD(每日驱动器写入)设置为1适合许多用例。
DWPD衡量您一天可以覆盖驱动器整个大小的次数。
对于500 GO磁盘,DWPD到1意味着理论上您可以在未达到产品保修政策期限的情况下每天写入500 GO。
一般在5到10年之间。
因此,如果每天执行数百万次构建,那么每次构建时创建的一些临时文件(100个或更多)几乎什么都没有。

此外,由于这种考虑,您不应该使代码或测试变得更复杂。
SSD可以使开发人员更轻松,而不是更复杂。

话虽如此,在单元测试中避免写太多文件仍然有意义,因为必须快速执行测试。
您可以更改测试类的API,以使其也接受ByteArrayInputStreamByteArrayOutputStream。这样,读取和写入将在内存中进行,而不是在文件系统中进行。

答案 1 :(得分:0)

  

您将如何处理?

我将重构代码,以便使用测试双精度(也称为模拟) 是一个选项。

具体来说,我希望创建这样的接缝

  1. 实现I / O的代码太简单了,以至于不能失败
  2. 所有复杂的代码都不关心I / O的实现方式。

在像Java这样的语言中,接缝将是一个接口。我的I / O代码会实现接口,但本身不会在测试中运行。

相反,该测试将使用合适的双重测试-实现相同接口但实际上不执行磁盘写入操作。

注意:如果我想要模拟各种写入错误的测试,以确保复杂的逻辑能够正确处理这些故障,则可能会有多种类型的双重测试。

生产代码的composition root当然需要创建要使用的“真实”实现的实例。但是测试的组合根目录可以选择测试双倍,内存文件系统或其他确保测试结果具有确定性的选项(顺便说一下,不要占用SSD的使用寿命)。

Hoare

是我们对幕后代码的启发
  

[构建软件设计]的一种方法是使其变得如此简单,以至于显然没有缺陷