【发布时间】:2015-07-11 00:16:48
【问题描述】:
我们正在尝试使用 TDD 来创建我们的系统,但我们遇到了无法确定正确的 TDD 行动方案的情况。
我们已经将文件 IO 隐藏在一个接口后面,如下所示:
public interface IFileIo
{
byte[] Read(string fileName);
void Write(string filename, byte[] data);
}
现在我们正在创建一个 InMemoryFileIo,我们可以使用它来代替我们将用于生产的真正的 SystemFileIo 类。
我们要确保这个InMemoryFileIo 正常工作,并且在某些情况下我们想用它来代替实际的文件系统,所以它应该是“生产质量”。
问题是,以“正确的 TDD 方式”做所有事情,我们如何为 .Read() 或 .Write() 创建不相互依赖的测试?
为了测试.Read() 是否正常工作,我们需要先成功调用.Write(),同样,为了测试.Write() 是否正常工作,我们需要在之后调用.Read() .通过这样做,我们实际上创建了两次相同的测试(排列,然后写入,然后读取,然后断言)。
假设我们有两个测试,一个测试.Read(),另一个测试.Write()。如果其中任何一个功能不起作用,那么两个测试都会失败。这违反了“一个测试应该只有一个失败的原因”的原则。
这里的示例是针对文件 IO 的,但是我们在使用数据库时也遇到了同样的问题(测试 put 没有 get)。
【问题讨论】:
-
在这种情况下很好,只需将它们一起测试 - 一个失败将意味着另一个失败,并且测试中的错误消息会告诉你在你可以的情况下哪个失败了查出。不要想太多,也不要试图使用任何虚假的模拟反射东西——它在这里是同一个单元内的,这是有道理的。
-
InMemoryFileIo 在其构造函数中采用
byte[]而不是创建它(依赖注入)的“正确”方式(同样,不用担心)预先设置要读取的数据或对彼此外部写入的数据运行检查 - 真的,不要想太多 - 只需编写对您有意义的测试并帮助清楚地识别系统中的缺陷。 -
我认为值得指出的是,如果您的内存 IO 类仅用作测试替身,那么它应该足够简单,无需进行大量测试。关键是对依赖于接口的其他类进行 TDD 处理是假的,对吗?将他们的通过或不通过测试与您的内存文件 IO fake 是否无错误相结合对我来说似乎是一个潜在的坏主意。我建议保持你的存根简单。
标签: unit-testing testing tdd