TDD是否意味着无论多么复杂,我都必须为每个方法编写一个测试?

3

假设我有一个用户类,其中有一个方法is_old_enough?

该方法只检查年龄是否超过18岁。看起来非常简单。

TDD是否意味着我必须为此编写一个测试,即使它很琐碎?

class User
  def is_old_enough?
    self.age >= 18
  end
end

如果这样做,为什么?编写测试的好处是什么?你只需要测试x >= y是否按照预期工作,而不是测试>=运算符的工作方式。
因为我看到最可能发生的情况是以下情况:
事实证明年龄实际上应该是21岁。那是一个bug,测试没有捕捉到,因为在编写代码时他们有错误的假设。然后他们进去并将方法更改为>= 21。但现在测试失败了!所以他们不得不去修改测试。因此,测试没有帮助,实际上在重构时给出了错误的积极警报。
看起来像这样简单的方法的测试实际上并没有测试任何有用的东西,而且实际上会伤害你。

我认为“测试驱动”意味着你要测试你的代码。这并不意味着你必须变得愚蠢。另一方面,有时相对简单的代码可能会有一个错误。如果有人在一个地方更改了定义,测试可能会在另一个地方失败。你需要进行积极和消极的测试(例如,“通过18,失败17”)。如果限制改为16,你的第二个测试现在将失败。我总是告诉人们:“当你学习新东西时,不要拔掉常识模块以腾出空间来容纳新信息”。 - Floris
使用TDD,你不是为一个方法编写测试,而是为测试编写一个或多个方法。首先编写一个描述所需但尚未实现行为的测试。然后编写必要的代码使测试通过。 - Mike Stockdale
2个回答

4
我认为你把测试覆盖率和测试驱动开发混淆了。TDD仅是一种实践,即开发自动化测试以验证某个新功能的用例。通常情况下,它开始时会失败,因为你已经存根了功能或者只是没实现它。接下来,你开发该功能直到测试通过。
这种做法让你在开发验证重要用例/特性的测试时保持头脑清醒。如果你认为这些用例已经被定期的特性测试覆盖到,这并不一定意味着你需要测试简单函数。
在覆盖率方面,这真的取决于你作为开发者(或团队)的决定。显然,希望测试与API的数量大致相等,但是你可以选择是否认为实施"is_old_enough?"总是足够容易。现在可能看起来很容易,但未来可能会改变。当你决定是否编写测试时,你只需要注意这些决策即可。尽管如此,你的用例很可能不会改变,测试也很容易编写。在代码各个方面感到自信从来都没有坏处。

1
我认为这个问题更多涉及单元测试而不是特定的TDD。
简短回答:关注行为。
长回答:有一句很好的话:“BDD是正确实施TDD”,我完全同意。虽然BDD和TDD在很大程度上是“相同”的事情(请注意,它们并不相等!),但对我来说,BDD为TDD提供了上下文。你可以在互联网上阅读很多相关内容,所以我不会在这里写文章,但是让我说:
在你的例子中,是的,测试是必要的,因为用户足够年龄是User实体的一种行为。测试为许多其他即将到来依赖于此信息的事情提供了安全保障,对我来说,测试会很好地记录这种行为(实际上,我倾向于阅读测试以找出开发人员在编写类时的想法-您可以了解到期望什么、类如何运作、边缘情况等)。
我真的看不出这个测试如何无法捕捉重构,因为我会在测试中考虑数字18、19、25和55(只是一堆很快很容易键入的断言)。
非常重要的一点是,单元测试只是你需要的技术之一。如果你的设计不足,你会发现自己写了太多没有意义的测试,或者你会遇到测试类做多个事情的麻烦等问题。你需要具备非常好的SOLID技能,才能以一种方式塑造出类,使得仅测试它们的公共接口(包括受保护的方法)实际上测试了整个类。正如前面所说,关注行为是关键。

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