如何正确使用 TDD

How to use TDD right

所以我在大学里有一个新任务,由很多人合作组成,我们想使用持续集成,考虑使用 CircleCI,我们想使用 TDD 方法。

我最大的问题是你如何正确使用TDD。我可能有错误的想法,但据我了解,你首先编写所有测试并使它们失败,因为你还没有任何代码,但如果我什至不知道所有的代码,我怎么能写我所有的测试我会 have/need?

在这种情况下,因为使用了 CircleCI,假设它不会让我合并代码,如果它没有通过测试,这怎么行?由于将编写测试但没有专门用于该测试的代码。 我错了吗,您在开发功能时编写了测试? 这是一个我真的很难掌握的主题,但我真的很想正确理解它,因为我相信它会对未来有所帮助。

My biggest question is how do you correctly use TDD. I might have the wrong idea but from what I understand you write all your tests first and make them fail, because you don't have any code yet, but how can I write all my tests if I don't even know yet all the units I will have/need?

不太正确。

您可以先思考问题,然后创建一个检查清单,列出您希望在完成之前实施的测试。

但实际执行周期是递增的。我们一次进行一个测试,从第一个开始。在我们引入第二个测试之前,我们让该测试通过,并清理所有代码。

这里的想法是我们将边走边学 -- 我们可能会考虑更多的测试,将其添加到清单中,或者我们可能会决定我们认为重要的测试不在之后所有,所以他们从清单上划掉了。

在任何给定的时间点,我们期望要么 (a) 所有已实施的测试都通过,要么 (b) 只有一个已实施的测试失败,而这就是我们目前正在处理的测试。每当我们发现其他条件成立时,我们就会后退,恢复到以前很好理解的状态,然后再次前进。

我们通常不会 push/publish/share 在测试失败时编写代码。相反,测试和工作实现是一起共享的。我们不分享损坏的中间阶段或已知错误;相反,我们分享进步。

查看 Bowling Game Kata 中的幻灯片可能有助于弄清作品的节奏。

感觉第一次测试很困难是完全正常的——您正在针对尚不存在的代码编写测试实现。我们倾向于在这里运用想象力;假设您需要的生产代码已经存在,您将如何调用它?你会传递什么数据给它?你会得到什么数据?你编写测试时就好像你想做的事情的完美接口已经存在一样。然后创建与该接口匹配的生产代码;然后你给那个生产代码正确的行为;然后你给生产代码一个设计,让代码以后容易改变。

当您对所有这些感到满意时,您将引入第二个测试,它通常看起来像第一个测试,但数据略有不同,预期结果也不同。所以第二个测试失败了,然后你去你之前写的易于更改的代码,并对其进行调整,以便第二个测试也通过。然后您再次清理设计,以便轻松更改代码。

依此类推,直到您到达清单的末尾。