测试驱动开发背后的哲学

时间:2010-07-22 16:17:23

标签: ruby-on-rails tdd agile

我目前正在通过http://www.railstutorial.org/

它使用Rspec和TDD方法。我知道编写大量测试可以帮助你避免错误,因为你的应用程序变得更复杂,但我不明白为什么你会为简单的事情编写测试,例如页面标题的存在。您似乎最终编写了与实际代码一样多的测试。

从长远来看这是否更好,还是过度杀伤?

7 个答案:

答案 0 :(得分:8)

  

您似乎最终编写了与实际代码一样多的测试。

是的,有时比实际代码更多的测试。您似乎缺少的好处是,当您更改一些看似不相关的代码并且旧的测试中断时,对小事情的测试将有助于您。

让我们假设您稍后决定将页面标题生成抽象为帮助方法,为您构建所有页面标题。如果您已经进行了测试,那么您将知道您的助手正在工作(或不工作)。

答案 1 :(得分:3)

答案 2 :(得分:3)

测试工作的基本原则是,对于任何具有N个分支的给定代码段,随后有多达2个 N 可能的路径可以通过该代码。这意味着对于某些可能实际上非常小的方法,可以使用的方法数量比方法本身要多得多。

这是一个常见的场景:

if (@user.posts.count > @limit.posts)
  # Branch 1
  flash.now[:error] = "You have posted too many times today."
elsif (@user.suspended?)
  # Branch 2
  flash.now[:error] = "Your account is suspended. You cannot post."
else
  if (@post.special? and !@user.can.post_special?)
    # Branch 3
    flash[:warning] = "You cannot create special posts."
    @post.special = false
  # else
    # Branch 4
    # Not branching also has to be tested
  end

  if (@user.recently_created?)
    # Branch 5
    @post.newbie = true
  # else
    # Branch 6
  end

  # Branch 7
end

unless (flash[:error])
  @post.save!
end

虽然这非常简单,但创建导致逻辑流经正确分支的环境却不是。您可能必须为每个特定的一个编写测试用例。这并不总是微不足道的,但是如果你有许多准备好的装置或工厂方法来构建几乎准备就绪的东西,你可以更容易。

如果不使用自动测试对每个案例进行测试,则由于无意的更改而导致故障的可能性很大。为了确保它正常工作,你必须手动运行这些路径,通常你会忘记一个,以后这会造成麻烦,可能是令人尴尬的变种。

减少测试的方法是通过消除不增加业务价值的业务逻辑来降低代码复杂性。只保留最迫切的东西,丢弃任何多余的东西。

如果你正在为一些应该简单的事情编写一千种不同的测试,那么在设计方面它可能不够简单。

答案 3 :(得分:2)

在我的团队中,我们为UI以外的所有内容编写了单元测试。 有一些工具可以帮助测试用户界面,但我们认为用户界面(如标题)太动态,无法测试。

这就是为什么在为网络编码时,很多人更喜欢MVC设计模式,它会在ui和后面的代码之间产生很大的分离,所以它允许你用单元测试覆盖几乎所有的代码。

是的,我们写了很多单元测试!!这是了解代码真正有用的唯一真实方式!

答案 4 :(得分:2)

It seems that you end up writing as many tests as actual code

这就是主意。

答案 5 :(得分:2)

有一组测试总是需要运行,即使设置标题是TDD背后的想法。那样你就永远不会推动生活并且说“doh,标题不再存在”。你有一套回归测试,所以当你越来越多地处理一个项目时,当你在一个项目没有被触及几个月之后再回到项目时,你最终不会破坏它。

此外,当我编写测试时,它迫使我真正考虑问题而不是仅仅抛出代码。我发现在使用TDD或BDD时我需要重构一点。我坐下来写的代码因为我匆忙而最终变得草率。也许只有我,我需要TDD来让我走上直线和狭窄的道路。

答案 6 :(得分:2)

在项目的设计周期期间,TDD强迫您在编写任何代码之前考虑应用程序的代码接口。反过来,这会迫使您考虑您尝试解决的实际问题,而不仅仅是编写一些代码,如Geoff Lanotte mentioned

另外,因为单元测试集中在一个单元上,所以你也可能编写集中和可重用的类,而不是紧密耦合的类。

开发周期期间,您只需编写使单元测试通过所需的代码。您不必再担心设计细节,让您专注于实际实施。

在产品的生命周期期间,维护工作更容易,因为您的测试套件会快速告诉您代码中的更改是否已经破坏。