【发布时间】:2010-07-22 16:17:23
【问题描述】:
我目前正在处理http://www.railstutorial.org/
它使用 Rspec 和 TDD 方法。我知道随着您的应用程序变得越来越复杂,编写大量测试可以帮助您避免错误,但我不明白您为什么要为简单的事情(例如页面标题的存在)编写测试。看起来你最终编写的测试与实际代码一样多。
从长远来看,这会更好,还是矫枉过正?
【问题讨论】:
标签: ruby-on-rails tdd agile
我目前正在处理http://www.railstutorial.org/
它使用 Rspec 和 TDD 方法。我知道随着您的应用程序变得越来越复杂,编写大量测试可以帮助您避免错误,但我不明白您为什么要为简单的事情(例如页面标题的存在)编写测试。看起来你最终编写的测试与实际代码一样多。
从长远来看,这会更好,还是矫枉过正?
【问题讨论】:
标签: ruby-on-rails tdd agile
看来您最终编写的测试与实际代码一样多。
是的,有时测试比实际代码多。您似乎缺少的好处是,当您更改一些看似不相关的代码并且您的旧测试中断时,对小事情进行测试会有所帮助。
假设稍后您决定将页面标题生成抽象为一个帮助方法,该方法为您构建所有页面标题。如果您已经进行了测试,那么您就会知道您的助手正在工作(或不工作)。
【讨论】:
与生成回归套件一样有价值或可能更有价值,TDD 是一种设计实践,旨在生成最简单的东西、低耦合的对象以及具有其他理想质量特征的代码
AgileData.org 这么说 this way:
TDD 的目标是规范而非验证。换句话说,这是在编写功能代码之前仔细考虑设计的一种方式。
您可能会发现整篇文章很有趣,尤其是Myths and Misconceptions。
而且,是的,您最终可能会得到与产品代码相似的测试代码行数。从业者认为,当更改成本高昂时,您会在编写测试之前完成工作,或者在最后完成工作(可能还有更多工作),修复错误。
【讨论】:
测试工作的基本原则是,对于具有 N 个分支的任何给定代码段,随后您可以通过该代码采取多达 2N 条可能的路径。这意味着对于一些实际上可能很小的方法,它可以使用的方法数量可能比方法本身要多得多。
这是一个常见的场景:
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
虽然这很简单,但创建将导致逻辑流过正确分支的环境却不是。您可能必须为每个特定的测试用例编写一个测试用例。这并不总是微不足道的,但是如果您有许多准备好的夹具或工厂方法来构建几乎可以使用的东西,那么您可以使其变得更容易。
如果不使用自动测试来测试每个单独的案例,由于疏忽更改而导致故障的可能性很大。为确保其正常工作,您必须手动运行这些路径,而且您通常会忘记其中一个,然后这会导致麻烦,可能是令人尴尬的各种路径。
例如,减少测试的方法是通过消除不会增加业务价值的业务逻辑来降低代码复杂性。只保留最重要的东西,丢弃任何多余的东西。
如果您要为应该很简单的东西编写一千种不同的测试,那么在设计方面可能还不够简单。
【讨论】:
It seems that you end up writing as many tests as actual code
就是这样。
【讨论】:
拥有一组即使设置标题也始终需要运行的测试是 TDD 背后的理念。这样一来,您就永远不会推动某些东西去生活并说“doh,标题不存在了”。您有一组回归测试,因此当您越来越多地从事一个项目时,当您在几个月未动过一个项目后回到项目时,您最终不会把事情搞砸。
此外,当我编写测试时,它迫使我真正思考问题,而不是仅仅把代码扔在那里。我发现我在使用 TDD 或 BDD 时需要更少的重构。我只是坐下来写的代码,因为我很着急,结果很草率。也许只有我一个人,我需要 TDD 才能让我走在笔直狭窄的道路上。
【讨论】:
在我的团队中,我们为除 UI 之外的所有内容编写了单元测试。 有一些工具可以帮助测试 UI,但我们认为 UI(如标题)过于动态而无法测试。
这就是为什么在为 Web 编码时,很多人更喜欢 MVC 设计模式,它在 ui 和代码背后创建了很大的分离,因此它允许您使用单元测试覆盖几乎所有代码。
是的,我们编写了很多单元测试!这是了解您的代码是否真正有效的唯一真正方法!
【讨论】:
在项目的设计周期中,TDD 迫使您在编写任何代码之前考虑应用程序的代码接口。这反过来又会迫使您考虑您要解决的实际问题,而不是像Geoff Lanotte mentioned那样仅仅编写一些代码。
此外,由于单元测试专注于单个单元,您还可能编写专注且可重用的类,而不是紧密耦合的类。
在开发周期中,您只需编写使单元测试通过所需的代码。您不必再担心设计细节,让您专注于实际实施。
在产品的生命周期中,更容易进行维护工作,因为您的测试套件会很快告诉您代码中的更改是否有任何问题。
【讨论】: