2014-09-05 72 views
0

最近我想通过开发一个真实的东西来学习TDD,所以我决定使用简单的数据打包器/解包器。在纸上设计完成后,一切看起来不错,但是当我尝试编码时,我意识到我不知道如何测试它,所以在TDD中 - 如何做任何事情。在TDD中测试两路依赖类

我有两个类:ArchiveReaderArchiveWriter。问题是,当我用ArchiveWriter保存某些东西时,如果没有它,我不能正确测试它,我不得不逐一比较输出字节,我认为这不是个好主意 - 稍后可能会发生较小的不相关的更改。 ArchiveReader测试也需要阅读,所以我必须使用ArchiveWriter来制作测试包。

TDD是否在这方面失败?有没有任何方法来测试这种情况?

+1

如果我正在测试读取或写出一些字节的东西,我想检查它是字节为字节的完美。 – 2014-09-08 13:26:11

回答

5

如果您已经有两个类的代码,那么它不是真正TDD,因为测试没有驱动设计

您仍然可以测试您的代码,具体取决于如何处理这些类的依赖关系。例如,如果ArchiveWriter类写入流,则可以将其输出到内存流而不是文件流,作者不应该关心它是什么样的流,而是可以让您比较写入方法。

同样适用于ArchiveReader类,如果它从流中读取,则它可以是存储器流。

至于你关于ArchiveWriterArchiveReader的问题相互依赖于验证对方,我不认为这是一定的问题。尽管能够独立测试两者是理想的,但是没有规定单元测试只能测试一个类。

对于这些类,在生产中,它们可能总是相互使用,如果以后再读不出来,那么写一个档案是毫无意义的。

+0

即使没有代码,听起来这些类的界面在编写测试之前就已经确定了,所以仍然没有足够的空间来编写测试来通知设计。如果你开始编写一个测试来验证读取和写入档案的行为,你最终会得到这两个类还是一个不同的(可能更好的)接口? – Jonah 2014-09-05 21:02:36

+0

我还没有做任何代码。也许我错过了一点,但我没有看到检查流内容和文件内容有什么区别,在我看来困难是相同的 - 它仍然像逐字节操作。你是在暗示这条道路?那么怎么处理发生在某些特定事件中的设计的少许更改,标题中的额外字段等等。为了满足要求,进行测试以满足要求?我认为在TDD中只是添加测试既不删除也不执行它们。 – gecio 2014-09-06 19:59:24

+1

在测试中,您尝试使用一个逻辑断言(对于'ArchiveWriter'),测试可能是结果具有正确的标头,另一个测试可能是正确的元数据,另一个测试可能是它具有正确的文件名另一个可能是档案里面有一个md5散列用于验证等等。如果你能想出10个不同的东西需要对代码进行断言,那么有10个或更多的测试并不是不合理的。事实上,您可能有更多测试非成功案例。进行具体的测试,并首先编写退化案例。 – Matthew 2014-09-06 21:48:10

1

TDD几乎约为单元测试。单元测试是关于完全隔离的独立工作单元的测试。简而言之,就是测试某些公开方法的某些逻辑,并假定所有依赖和环境都是伪造的。

在你的例子中,它意味着如果你想单元测试ArchiveReader或者ArchiveWriter,首先你应该将它与真正的I/O隔离并且测试逻辑(C#/ java/...“你的代码”)。

如果您以复杂的方式测试您的应用程序,那么主要是关于集成测试。因此,您的断言需要抵制ArchiveWriter产生的文件。

在进入TDD之前,我建议您阅读至少一本关于单元测试的好书。罗伊·奥谢罗夫的书对我来说非常完美。

2

我开发了这种类型的代码,它有两个类或方法,必须使用TDD一直读取和写入相同的二进制格式。

你提到检查输出逐字节。我更喜欢输入代码的类似测试,因为虽然我必须手工制作二进制输入,但输入代码的行为通常更容易检查。它将委托给方法或创建对象,您可以按照通常的方式正确地检查它。

我也有对称性测试。这些代码使用输出代码创建二进制表示,然后让输入代码从该二进制表示中创建一组新的对象。测试检查原始对象和新对象是否相同。这些测试很容易编写,并在失败时生成有用的duagnostics。

现在有些人会说哦,但是你没有进行单元测试,因为你的对称测试测试了输出代码和输入代码;你正在做集成测试因此做错了。这不应该担心你。在进行集成测试之前,单元测试和集成测试之间存在精细划分,并且所有内容都必须通过单元测试进行测试的想法是错误的。实际上,几乎没有代码被完全隔离地测试;大多数测试代码使用其他类,即使它们的基础知识如StringHashMap。将测试视为在完美单元测试和完美集成测试之间的连续体,更偏向于所有代码在单元测试结束时进行测试,而不是在某些代码不这样做的时候过于担心。