1

根据维基百科,以下是 TDD 中的步骤:

第一步:编写单元测试

第二步:运行单元测试

第三步:编写模块代码

第 4 步:再次运行所有测试

第五步:清理代码

第6步:重复步骤

问题1:在TDD中我们主要写单元测试。集成测试和系统测试在上述步骤中的位置是什么?

考虑以下示例:

假设我们有一个必须开发的功能。然后根据 TDD,我们将在短期迭代中开发此功能。假设我们将此功能分为 2 个模块 - 模块 1 和模块 2。我正在编写迭代步骤,以根据上述给定步骤在 TDD 中开发这些模块。(问题2)请在以下步骤中纠正我的错误

**迭代 1:**

第 1 步:我们为模块 1 编写单元测试。

第 2 步:为模块 1 运行此单元测试(此测试将失败)

第 3 步:为模块 1 开发代码。

第 4 步:再次为模块 1 运行单元测试(此测试将通过)

**迭代 2:**

第 1 步:为模块 2 编写单元测试

第 2 步:为模块 2 运行单元测试

第 3 步:为模块 2 编写代码

第 4 步:运行模块 1 的单元测试和模块 2 的单元测试。(问题 3:在此步骤中,为什么我们在模块 2 处于测试状态时运行模块 1 的单元测试?如果你说这样做是因为要测试模块 2 是否不会破坏模块 1 的功能,那么我的问题是,这里我们只测试模块 2。它还没有与模块 1 集成,那么它将如何破坏模块 1?)

**第 3 次迭代:**

第 1 步:创建集成测试(我在这里吗?

第 2 步:运行集成测试(它们将失败,因为模块 1 和模块 2 尚未集成)

第 3 步:集成模块 1 和模块 2

第 4 步:运行所有测试(模块 1、模块 2 和集成测试的单元测试)

(问题 4:为什么在这一步我们要运行模块 1 和 2 的单元测试?)

迭代 4(当所有模块都集成时):

步骤 1:创建系统测试

第 2 步:运行系统测试(它们会失败)

第3步:(问题5:)我应该在这里写什么代码,因为系统测试我们不写任何代码,根据TDD原则,我们先写测试,然后再写开发代码,那么我们在这里写什么代码?

4

2 回答 2

7

在我看来,您的工作流程略有倒退。在优秀的书Growing Object Oriented Software Guided By Tests中,建议您从更高级别的测试开始,通常是代表您要添加的功能的“集成测试”,并以此作为您想要的行为的驱动力看。

当此集成测试通过时,您就知道您已经完成了该功能。

一旦你有了这个失败的测试(作者称之为外循环),你就开始内循环的 TDD 过程,即为你需要实现所需功能的类创建测试。你通过创建一个测试来做到这一点,编写代码让它通过。然后运行所有测试。您的外部测试可能仍然会失败。然后实现另一个单元测试,然后是所需的实现。重复此过程,直到您创建了所有必要的类以使外部测试通过。

然后通过编写一个新的外部测试再次重复整个过程。

对我来说,最重要的是找到一个适合你的流程,并且要务实。不要被迫放弃任何教条的方法,因为与任何事情一样,编写软件会因您正在编写的内容、与您一起编写它的人、您可用的工具以及许多其他因素而异。时刻准备好改变你自己的过程,并不断地重新评估它,根据你自己的经验,也根据你的同事和你尊重的人的经验。没有人有完美的解决方案,因为事情总是会变得更好。

编写 Rhino Mocks 的说他很少再使用模拟框架了在 .NET中编写依赖注入的说他很少再使用 IoC 容器了。灵活务实。

我发现我倾向于更多地关注外部集成测试而不是单元级测试,因为这迫使测试测试代码的行为而不是实现。我发现,当我为每个实际类创建一个测试类时,重构代码变得非常昂贵,因为我不仅必须更改所有类,而且还必须同时重构所有测试。当测试专注于代码逻辑单元的行为时,通常当我重构该代码的类结构时,测试保持不变,因为我只是重新组织内部结构,而不是外部行为。

@CarlManaster 所说的关于 BDD 的内容也非常相关。我发现 BDD 比 TDD 更有用,主要是因为重点从测试转向行为。行为是您想要的,而不是大量的测试(尽管这也可以很好。)

至于要运行哪些测试,对我来说,你可以运行的测试越多越好。令人惊讶的是,“孤立”的变化经常会莫名其妙地导致其他东西崩溃。将整个系统中每个更改的后果牢记在心,这并不像您想象的那样简单,即使对于小型系统也是如此。

我的首选工具是NCrunch。它删除了编码的停止/构建/运行测试部分。您只需编写测试,编写代码。等待几秒钟。变绿。重复。改变了我的生活; 值他收费的两倍。

于 2015-08-04T09:47:25.270 回答
1

测试驱动开发倾向于关注单元,因此也关注单元测试。一种附属方法,行为驱动开发,或 BDD,在更高层次上推动设计,从而在更高层次上进行测试;验收测试和集成测试可能在 BDD 中发挥作用。TDD 不排除集成测试,但它们不是实践的一部分。正如您所说,这种做法是一次编写一个对一小部分功能的小测试,使该测试通过,清理您的代码并进行迭代。这就是所有的单元测试。

如果您的第一个功能正常工作,那么将您的第二个工作功能与其集成应该可以正常工作 - 至少在理论上是这样。TDD 为您提供了这两个工作特性,但您当然需要集成它们,当然您还需要测试来验证集成是否有效。但这不是 TDD 实践的一部分。TDD 说的是,当您的集成测试失败时,这是某个较小的功能单元失败的结果,并且您未能充分测试该功能单元。与其尝试修复它,不如编写演示失败的单元测试。使该测试通过,您的集成测试现在也将通过。系统测试也是如此。

于 2015-08-03T18:24:22.997 回答