根据wikipedia以下是TDD中的步骤:
第1步:编写单元测试
第2步:运行单元测试
第3步:为模块编写代码
第4步:再次运行所有测试
第5步:清理代码
第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:在此步骤中,为什么我们运行模块1的单元测试,因为模块2正在测试中?如果你说这样做是因为为了测试模块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原则,我们首先编写测试然后编写开发代码,以便我们编写什么代码这里吗
答案 0 :(得分:7)
在我看来,你的工作流程略微落后。在优秀的书Growing Object Oriented Software Guided By Tests中,建议您从更高级别的测试开始,通常是一个“集成测试”。表示您要添加的功能,并将其作为您要查看的行为的驱动程序。
您知道在此集成测试通过后您已完成此功能。
一旦你有这个失败的测试(作者称之为外部循环),那么你就开始内部循环上的TDD过程,即为实现所需功能所需的类创建测试。你这样做是通过创建一个测试,编写代码使其通过。然后运行所有测试。可能你的外部测试仍然会失败。然后实现另一个单元测试,然后执行所需的实现。重复此过程,直到您为外部测试创建了所有必需的类。
然后通过编写新的外部测试再次重复整个过程。
对我来说,最重要的事情是找到一个适合你的过程,并务实。不要像任何事情那样强迫任何教条方法,编写软件会因你正在编写的东西,你正在编写它的人,可用的工具和许多其他因素而异。始终准备好根据自己的经验改变自己的流程并不断重新评估,并根据您与之合作并尊重您的经验。没有人拥有完美的解决方案,因为事情总能变得更好。
The guy who wrote Rhino Mocks有said he rarely uses mocking frameworks anymore。 The guy who写道Dependency Injection in .NET说他rarely uses IoC containers anymore。要灵活务实。
我发现我倾向于更多地关注外部集成测试,而不是专注于单元级测试,因为这会强制测试测试代码的行为而不是实现。我发现当我为每个实际的类都有一个测试类时,重构代码变得非常昂贵,因为我不仅要更改所有类,而且还必须同时重构所有测试。当测试集中在代码的逻辑单元的行为时,通常当我重构该代码的类结构时,测试保持不变,因为我只重新组织内部结构,而不是外部行为。
@CarlManaster关于BDD的内容也非常重要。我发现BDD比TDD更有用,因为主要是从测试到行为的重点转移。行为是你想要的,而不是一大套测试(虽然这也很好。)
至于要运行哪些测试,对我来说,您可以更频繁地运行的测试越多越好。令人惊讶的是,一个被隔离的变化经常发生。可以莫名其妙地导致其他东西破裂。将整个系统中的每一个变化的后果牢记在脑中并不是一件简单的事情,就像你可能想到的那样,即使是小型系统。
我首选的工具是NCrunch。它删除了编码的停止/构建/运行测试部分。你只需编写测试,编写代码。等几秒钟变绿。重复。改变了我的生活;值得加倍他的收费。
答案 1 :(得分:1)
测试驱动开发倾向于关注单元,因此关注单元测试。附属方法,行为驱动开发或BDD,可以在更高层次上推动设计,从而在更高层次上进行测试;验收测试和集成测试可能在BDD中发挥作用。 TDD不排除集成测试,但它们不是实践的一部分。正如您所说,这种做法是一次编写一小部分功能的微小测试,让测试通过,清理代码并进行迭代。这都是单元测试。
如果您的第一个功能正在运行,那么将第二个工作功能与它集成应该可以正常工作 - 至少在理论上如此。 TDD为您提供了这两个功能,但当然您需要集成它们,当然您需要测试来验证集成是否有效。但这不是TDD实践的一部分。 TDD所说的是,当您的集成测试失败时,这是一些较小的功能单元失败的结果,并且您未能充分测试该功能单元。不要试图修复它,而是编写演示失败的单元测试。让测试通过,您的集成测试现在也将通过。系统测试也是如此。