使用TDD规划单元测试

6
当你要编写一个类的单元测试时,你是如何计划的?
你是否遵循正式的模板,还是使用笔和纸/记事本?
我正在寻找一些方法,让其他程序员/QA知道应该实现哪些测试(如果有什么被忽略了,那么更容易发现)。
5个回答

7
使用TDD,测试驱动你正在编写的功能。如果你需要为其编写正式模板,那么很可能你并没有进入其中的精神!
在编写代码时应该使用TDD来生成测试用例。简单地说,在编写下一行代码之前,将代码应该执行的内容编码到一个测试中。
查看Bob Martin的保龄球游戏示例,这应该让你更加了解TDD的感觉。

我还想补充一点,如果你正在进行TDD,并想记下你仍需要编写的测试,我使用索引卡和铅笔。其他人会编写测试方法并标记为被忽略。 - bcarlso
@bcarlso:这正是我正在寻找的东西。一种跟踪已经实现了哪些测试和尚未实现了哪些测试的方法。 - the_drow

1

我认为使用模板与使用TDD不太相符。我假设你已经读过Kent Beck的《测试驱动开发:实例》一书。如果没有,请务必阅读。

但是,总体思路很简单。当我们开始一个类时,我们会对该类的职责有一个大致的了解。这是我们使用的步骤:

  1. 对类的职责有一个大致的了解,并使用该信息来命名类。

  2. 为该类创建一个测试用例。

  3. 如果您从具体信息开始了解类内部的单元,只需在类内编写这些存根并为这些存根编写测试用例。最初,所有这些方法都将失败,并且大多数方法的签名将更改。这就是整个思路。

  4. 在大多数情况下,开发人员可能没有那么多信息。在这种情况下,在第一个测试中编写代码是可以的。一旦测试通过,然后将逻辑迁移到类中。

所以我的观点是,TDD的整个重点是使开发过程更加有机。随着对其应该执行的操作的了解而增长。拥有正式的模板或书面记录可能不会有所帮助。

唯一我能想到的事情,就是在每个迭代之前与开发人员坐下来,并对每个组件类及其职责制定相当详细的想法(我们仅使用此讨论来最终确定公共API)。
如果您想了解开发人员编写的测试用例质量,那么您可以进行临时代码审查,以查看类是否正确拆分为单元并且所有单元都经过了测试。

我在这里谈论的是类似于清单的东西。比如说,方法DoFoo可能会抛出ArgumentNullException和InvalidOperationException。不知何故,我必须确保我已经编写了所有所需的失败测试(这个术语是否正确?)。我谈论的是一份文件,它指定了某个方法的预期结果。这个文件既可以提供参考,也可以作为沟通已经测试过什么(或应该测试但被遗忘了)的方式。这真的证明了TDD吗? - the_drow
你所看到的是工具支持。有一些非常复杂的测试覆盖分析工具,可以提供代码中未被测试覆盖的部分的统计数据。如果该方法编写正确的前置条件和后置条件,则该工具应该有助于衡量编写的测试的质量。 - uncaught_exceptions
那么你的意思是说提前考虑所有应该编写的测试并不值得吗?我已经知道了类的接口。确保编写所有测试不值得吗? - the_drow
@thedrow,每个案例都略有不同。我并不完全了解你的情况动态。在我看来,没有必要进行文档编写或思考时间。一旦所有组件都摆放好了,开发人员需要测试所有可能的程序流程。有工具支持来衡量单元测试的应用程度。如果我看到测试不好的情况,那么(我们公司有一个特别糟糕的开发人员...)你需要让他知道并培训他。 - uncaught_exceptions

1

TDD 不是你要找的方法论 ;-)

way to let other programmers/QAs know what tests should be implemented

这个声明意味着你正在进行测试,但是TDD本身是由需求驱动并产生特性的 - 它也产生了一套测试用例,这只是一个附带的(但非常强大)附属品,它恰好导致了回归测试套件。

虽然TDD利用“测试”来推动代码开发,但您不需要事先指定测试。即使您这样做(有时候这样做对于“思考”是有帮助的),您的程序员也可能不需要编写所有测试以产生所需的行为。实际上,在TDD中,当所有测试都通过时,鼓励您停止工作 - 您不需要继续编写测试,只是发现它们已经通过;这类似于无谓的工作。

TDD的另一个副作用是拥有(并持续运行)回归测试套件。如果在以后的某个日期发现了错误,仅凭测试套件就可以更容易地编写另一个测试,该测试用于演示具有失败测试的错误。一旦修复了错误,测试应该通过 - 连同套件中的所有其他测试一起。


1

你不能承诺使用TDD并让其他人进行单元测试。这个要求强烈表明你没有理解TDD范例。

根据我的(尽管相对较新的)经验:

  • 你编写测试,如果通过,将确认你对目标功能的初始理解。此时不编写任何生产代码。
  • 然后实现生产代码以使单元测试通过。
  • 如果你的理解发生变化,则更改单元测试或/和添加新的测试。
  • 然后实现生产代码中的更改以使测试通过。
  • 到那时,如果你发现你的生产代码的某些部分没有被覆盖,可以编写额外的单元测试。
  • 删除不再有意义的测试。
  • 最终得到美观、简洁、干净的代码 :o)

TDD不是QA方法;它是一种开发方式。整个想法是单元测试指导开发过程。因此,你真的不能让其他人为你做单元测试。


0

我通常从设计类开始,使用简单的UML类图。我尽量不让图表过于详细,以便可以对其运行测试(例如为每个方法指定参数和返回类型,并知道该方法的行为如何影响对象状态)。

然后,我编写单元测试。一般来说,当涉及到自动化测试时,您应该为类中定义的每个方法拥有1个测试方法。就惯例而言,如果我的类中有一个名为myMethod的方法,则我的单元测试方法将被称为testMyMethod

我使用我所知道的关于方法预期行为的知识编写单元测试,然后编写该方法并检查它是否通过了单元测试。


testMyMethod 是一个不太好的命名。有些工具可以根据格式化的测试名称生成漂亮的报告。对于名为 VerifyThat_WhenDoingFoo_NoExceptionIsThrown 的测试,有报告工具可以将该名称拆分为动作:When Doing Foo、期望结果:No Exception Is Thrown 和测试结果:Passed。 - the_drow
@the_drow 这些方法名仅用于说明目的。无论如何,大多数单元测试框架都能够根据类方法自动生成测试方法。 - Brian Driscoll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接