将TDD回溯应用到C#代码库的最佳选择

我有一个由5个C#库组成的现有框架,该框架自2006年以来使用得很好,并且是我大多数项目的主要代码库。 我公司希望出于软件质量的原因推出TDD; 通过许多教程和阅读理论,我了解TDD的好处。

时间不是无限的我需要为实际的方法制定计划。 据我所知,我看到的选项是:

A)可以使用一个测试项目来重叠来自所有5个库组件的对象。 一系列高级测试可能是最初被视为非常大的软件库的起点。

B)5个库组件中的每一个的测试项目。 这些项目将在最低级别测试function,与其他库组件隔离。

C)由于代码被广泛认为有效,因此只需对错误修复或新function添加unit testing。 使用重现错误的步骤编写一个测试,该测试在包含错误的逻辑上失败。 然后重新计算代码,直到测试通过。 现在您可以确信错误已得到修复,并且以后也不会在循环中引入

无论选择哪个选项,都可能需要“Mocking”来替换外部依赖项,例如:

  • 数据库
  • 网络服务
  • 配置文件

如果有人有任何更多的输入,这将是非常有帮助的。 我计划在Visual Studio 2010中使用Microsoft内置的MSTest。

我们有一百五十行代码库。 我们的方法是首先编写一些集成测试(您的选项A)。 这些测试几乎贯穿整个系统的端到端:它们从存储库复制数据库文件,连接到该数据库,对数据执行某些操作,然后将报告输出到CSV并将它们与已知良好的输出进行比较。 它们远非全面,但它们运用了我们的客户依赖我们的软件做的大量事情。

当然,这些测试运行得非常缓慢; 但六年后我们仍然连续运行所有这些(现在分布在八台不同的机器上),因为它们捕获了我们仍然没有进行unit testing的东西。

一旦我们有了一个不错的集成测试基础,我们花了一些时间在系统的高流量部分(你的选项B)中添加更精细的测试。 我们有时间这样做,因为我们的代码质量很差。

一旦我们将质量提高到一定的阈值,他们就开始要求我们再做一次真正的工作。 所以我们选择了为新代码编写测试的节奏(你的选项C)。 此外,如果我们需要对尚未进行unit testing的现有代码进行更改,我们可能会花一些时间在开始进行更改之前用测试覆盖现有function。

您的所有方法都有其优点,但随着时间的推移,您获得测试覆盖率,相对收益将会发生变化。 对于我们的代码库,我认为我们的策略很好; 集成测试将有助于捕获您在尝试破坏依赖项以添加unit testing时所犯的任何错误。

(A)和(B)都不能恰当地被认为是TDD。 代码已经写好了; 新测试不会推动其设计。 这并不意味着追求其中任何一条路径都没有价值,但将它们视为TDD是错误的。 关于“代码被广泛认为是有用的”,我怀疑如果你开始(B),你会发现它有一些漏洞。 未经测试的代码几乎总是包含错误。

我的建议是追求(B),因为我发现unit testing比集成测试更有价值(尽管更大的价值在于你为时已晚的设计优势)。 集成测试也很有价值,可以告诉你关于代码的不同重要事项,但我喜欢从unit testing开始。 选择5个组件中的一个并开始编写我们称之为特征测试的组件 。 开始发现行为,建立你编写unit testing的经验。 选择最容易测试的东西; 以你学到的东西为基础,逐步提升以测试棘手的比特。 在编写这些表征测试时,您几乎肯定会发现令人惊讶的行为。 请注意,当然,并考虑是否应该修复它(或修复是否可能破坏依赖于令人惊讶的行为的代码)。

当然, 实现它们的代码之前 ,为任何新function或错误修复编写测试。 祝好运!

根据定义,如果要为现有代码库创建测试,则不是TDD。

我会把C)作为一个给定:每当你有一个bug,写一个“certificate”这个bug的测试,并永远消除它。

我同意Carl Manaster的建议。 问题的另一个角度是“经济学”:为遗留应用程序编写测试可能会很昂贵,那么您将在哪里获得最大的收益? 考虑a)最常用的类和方法,b)最容易出错的类和方法(通常是代码复杂度最高的类)。

还可以考虑使用像Pex和Code Contracts这样的工具,这些工具可以帮助您考虑您没有考虑过的测试,以及代码中可能存在的问题。

我会选择选项C.试图围绕非unit testing设计的代码进行unit testing可能是一个重要的时间。 我建议只在你复制部分代码时添加测试,然后你可能必须重构该代码以允许它进行unit testing。

集成测试也可能需要考虑遗留代码,因为我认为它们比unit testing更容易实现。

选项A和B不符合TDD的定义,并且非常耗时。 我会选择选项C,因为它是最实用的解决方案。