Ruby on Rails – 为什么要使用测试?

我对Ruby on Rails中各种测试设备的用途感到困惑。 我已经使用该框架大约6个月,但我从来没有理解它的测试部分。 我使用的唯一测试是Java中的JUnit3,而且只是简单的。

我读过的所有内容都只显示了测试validation。 轨道中的validation不应该起作用吗? 看起来更像测试框架而不是测试代码。 为什么需要测试validation?

此外,对于代码中的任何更改,测试似乎都非常脆弱。 因此,如果您更改模型中的任何内容,则必须更改测试和灯具以匹配。 这不违反DRY原则吗?

第三,编写测试代码似乎需要很多时间。 这是正常的吗? 刷新我的浏览器并查看它是否有效会不会更快? 我已经不得不玩我的应用程序只是为了看它是否正确流动并确保我的CSS没有爆炸。 为什么手动测试不够?

我之前已经问过这些问题而且我没有得到“自动化测试自动化”。 我足够聪明,可以找出自动化任务的优势。 我的问题是,与好处相比,编写测试的成本似乎非常高。 也就是说,任何详细的回复都是受欢迎的,因为我可能错过了一两个好处。

轨道中的validation不应该起作用吗? 看起来更像测试框架而不是测试代码。 为什么需要测试validation?

Rails中的validation确实有效 – 事实上,Rails代码库中有unit testing来确保它。 当您测试模型的validation时,您正在测试validation的细节:长度,可接受的值等。您确保代码是按预期编写的。 一些validation是简单的帮助,您可以选择不测试它们“没有人可以搞乱validates_numericality_of调用”的概念。 真的吗? 是否每个开发人员都记得首先编写它? 每个开发人员都不会意外删除坏复制粘贴上的一行吗? 在我个人看来,你不需要为Rails的validation帮助器测试每个值的最后组合,但你需要一行来测试它是否通过了正确的值,以防万一punk在将来改变它没有经过适当的预见。

此外,其他validation更复杂,需要大量自定义代码 – 它们可能需要更彻底的测试。

此外,对于代码中的任何更改,测试似乎都非常脆弱。 因此,如果您更改模型中的任何内容,则必须更改测试和灯具以匹配。 这不违反DRY原则吗?

我不相信它违反DRY。 他们正在沟通(这就是编程,沟通)两个截然不同的事情。 测试说代码应该做点什么。 代码说明它实际上做了什么。 当这些东西之间断开连接时,测试非常重要。

显然,测试代码和应用程​​序代码密切相关。 我认为它们是硬币的两面。 你不会想要没有背部的前部,或没有前部的背部。 良好的测试代码强化了良好的应用程序代码,反之亦然。 这两者一起用于理解您试图解决的整个问题。 编写良好的测试代码是文档 – 它显示了应该如何使用应用程序代码。

第三,编写测试代码似乎需要很多时间。 这是正常的吗? 刷新我的浏览器并查看它是否有效会不会更快? 我已经不得不玩我的应用程序只是为了看它是否正确流动并确保我的CSS没有爆炸。 为什么手动测试不够?

你只参与过非常小的项目,测试可以说是足够的。 但是,当您处理一个包含多个开发人员,数千或数万行代码,与Web服务集成点,第三方库,多个数据库,数月开发和需求更改等的项目时,还有很多其他发挥作用的因素。 手动测试是不够的。 在任何真正复杂的项目中,一个地方的变化通常会在其他地方产生无法预料的结果。 适当的体系结构有助于缓解这一问题,但通过识别一个地方的变化何时破坏另一个地方,自动化测试也有助于(并帮助确定可以改进体系结构的点)。

我的问题是,与好处相比,编写测试的成本似乎非常高。 也就是说,任何详细的回复都是受欢迎的,因为我可能错过了一两个好处。

我会列出一些好处。

如果您先测试(测试驱动开发),您的代码可能会更好。 我没有见过一个程序员,他给了它一个坚实的镜头,但事实并非如此。 测试首先迫使您考虑问题并实际设计您的解决方案,而不是将其解决。 此外,它会强迫您充分了解问题域,如果您必须将其解决,您知道您的代码在您定义的限制范围内工作。

如果您有完整的测试覆盖率,您可以无风险重构。 如果软件问题非常复杂(同样,持续数月的现实世界项目往往很复杂),那么您可能希望简化以前编写过的代码。 因此,您可以编写新代码来替换旧代码,如果它通过了所有测试,那么您就完成了。 它确实完成了旧代码在测试方面所做的工作。 对于计划使用敏捷开发方法的项目,重构是绝对必要的。 总是需要做出改变。

总而言之,自动化测试,尤其是测试驱动开发,基本上是一种管理软件开发复杂性的方法。 如果您的项目不是很复杂,那么成本可能会超过收益(尽管我对此表示怀疑)。 然而,现实世界的项目往往非常复杂,测试和TDD的结果不言自明:它们起作用。

(如果你很好奇,我发现Dan North关于行为驱动开发的文章非常有助于理解测试中的许多价值: http : //dannorth.net/introducing-bdd )

测试应该validation您的应用程序逻辑。 就个人而言,我认为我最重要的测试是我在Selenium中运行的测试。 他们检查浏览器中显示的内容实际上是我期望看到的内容。 但是,如果这就是我所拥有的,那么我会发现它很难调试 – 它也有助于进行更低级别的测试,集成,function和unit testing都是有用的工具。 通过unit testing,您可以检查模型的行为是否符合您的预期(这意味着每个方法,而不仅仅是validatins)。 Validatins肯定会工作,但只有你做对了。 如果你弄错了,他们就会工作,但不是你想象的那样。 编写几行测试比以后调试要快。

一个简单的例子就像http://wiseheartdesign.com/2006/01/16/testing-rails-validations中的一个例子,只检查unit testing中的validation。 O’Reilly上的文章http://www.oreillynet.com/pub/a/ruby/2007/06/07/rails-testing-not-just-for-the-paranoid.html?page=1有点儿更完整(虽然仍然相当基本)。

自动化测试在回归测试中特别有用,在回归测试中,您可以更改某些内容并运行一组测试来检查您是否没有破坏任何其他内容。

测试是一种重复forms,但它们不会违反DRY,因为它们以不同的方式表达事物。 测试说“我做了X所以Y应该发生”。 代码说“X发生了,所以现在我需要做Z,这恰好会导致Y发生”。 即测试刺激原因并检查效果,而代码响应原因,并影响某些事情。

许多测试教程和Rails生成器创建的示例测试非常蹩脚,恕我直言,可以给人错误的印象,你应该测试像内置的Rails方法等愚蠢的东西。

由于Rails拥有自己的测试套件,因此编写或运行仅测试内置Railsfunction的测试没有意义。 您的测试应该运用您正在编写的代码! 🙂

至于运行测试与在浏览器中刷新的相对优点。你的应用程序越大,就越需要手动运行多个场景和边缘情况,以确保应用程序中没有任何内容。坏了。 最终,您将在每次更改后停止测试整个应用程序,并开始“现场测试”您认为应该受影响的区域。 不可避免的是,你会发现几个月以前曾经工作过的东西现在已经彻底破碎了,当它破裂或者哪些变化破坏了你时,你已经不确定了。 在那之后发生了足够多次……你会重视自动化测试…… 🙂

我还没有真正使用Rails,但是我认为这些自动化测试在烟雾测试中非常有用,可以确保您刚刚做的事情不会破坏您上周所做的事情。 随着项目的发展,这将变得越来越重要。

此外,在编写代码之前编写测试(使用测试驱动开发模型)将帮助您更好更快地编写代码,因为测试会强制您完全考虑问题。 它还可以帮助您了解将复杂方法分解为可以单独测试的较小方法的位置。

你是对的,编写和维护测试需要花费很多时间。 有时比代码本身更多的时间。 但是,由于上述原因,它可以节省您修复和重构错误的时间。

例如:我在一个25000+项目上工作(是的,在rails 1.2中),并且在上周一我告诉我,如果他们将“leave_date”属性设置为过去,我是否可以让除了管理员之外的每个列表中的用户消失。

您可以重写每个列表操作(50+)以放置一个

@ users.reject {|!U | Date.today> u.leave_date}

或者你可以覆盖“查找”方法(DRY ;-),但只有你有测试(在找到用户的所有东西上!)你才会知道你没有通过覆盖用户#find来破坏任何东西!

我读过的所有内容都只显示了测试validation。 轨道中的validation不应该起作用吗? 看起来更像测试框架而不是测试代码。 为什么需要测试validation?

有一个很好的Railscast显示了一种测试控制器的方法 。