什么不在Rails中测试?

时间:2010-09-02 18:28:54

标签: ruby-on-rails rspec testing

我已经写了一段时间的测试,我开始掌握一切。但是我有一些关于测试覆盖率真正需要的问题。共识似乎很清楚:更多的报道总是更好。但是,至少从初学者的角度来看,我想知道这是否真的如此。

以完全香草控制器动作为例:

def create
  @event = Event.new(params[:event])
  if @event.save
    flash[:notice] = "Event successfully created."
    redirect_to events_path
  else
    render :action => 'new'
  end
end

只是生成的脚手架。我们这里没有做任何不寻常的事情。为什么为此操作编写控制器测试很重要?毕竟,我们甚至没有编写代码 - 生成器为我们完成了工作。除非rails中存在错误,否则此代码应该没问题。看起来测试这个动作与测试,例如collection_select并没有太大的不同 - 我们不会这样做。此外,假设我们使用黄瓜,我们应该已经涵盖了基础知识(例如重定向的地方)。

对于简单的模型方法也可以这样说。例如:

def full_name
  "#{first_name} #{last_name}"
end

我们真的需要为这些简单的方法编写测试吗?如果出现语法错误,您将在页面刷新时捕获它。同样,只要你的功能点击任何调用full_name方法的页面,黄瓜就会捕获这个。显然,我们不应该依赖黄瓜来做任何过于复杂的事情。但是full_name真的需要单元测试吗?

您可能会说,因为代码很简单,测试也很简单。所以你不妨写一个测试,因为它只需要一分钟。但似乎写作基本上毫无价值的测试可能弊大于利。例如,它们使您的规格变得混乱,使得更难以专注于实际重要的复杂测试。此外,它们需要时间来运行(尽管可能不多)。

但是,就像我说的那样,我几乎不是专家测试员。我不一定主张减少测试覆盖率。相反,我正在寻找一些专家建议。是否真的有理由写这么简单的测试?

5 个答案:

答案 0 :(得分:9)

我的经验是,你不应该浪费你的时间来编写一些微不足道的代码, ,除非 你有很多复杂的东西依赖于正确性那种琐碎的事。我认为测试吸气剂和制定者这样的东西完全是浪费时间,但我确信那里会有不止一个报道的瘾君子愿意反对我。

对我来说,测试有三个方面:

  1. 他们保持不间断的旧功能如果我可以检查一下 我投入的任何新事物都没有破碎 通过运行测试我的旧东西,它是 一件好事。

  2. 当我重写旧东西时,他们让我感到安全代码我 重构很少是微不足道的 一。但是,如果我想重构 非常重要的代码,有测试 确保我的重构没有 打破任何行为是必须的。

  3. 他们是我工作的文档需要非常重要的代码 记录。但是,如果你同意的话 在我看来,代码中的评论是 魔鬼的工作,有明确的和 简明的单元测试,让你 了解正确的行为 某事物是(必须)。

  4. 我确信我不会破坏任何东西,或者我认为记录不自觉,我只是不浪费时间测试。你生成的控制器和模型方法,即使没有单元测试,我也会说都很好。

答案 1 :(得分:6)

更多的覆盖范围可以提高代码质量,但成本更高。这里有一个滑动刻度,如果你编写一个人造心脏,你需要更多的测试。您预先支付的金额越少,您支付的可能性就越大,也许很痛苦。

在示例中,full_name,为什么要在它们之间放置一个空格,并按first_name排序,然后是last_name-这有关系吗?如果稍后要求您按姓氏排序,是否可以交换订单并添加逗号?如果姓氏是两个字会怎么样 - 额外的空间会影响事物吗?也许你还有一个别人正在解析的xml feed?如果您不确定要测试什么,对于简单的未记录的函数,可以考虑方法名称隐含的功能。

我认为贵公司的文化也很重要。如果你做的比别人多,那你就是在浪费时间。如果主要内容是错误的话,没有一个经过良好测试的页脚是没有帮助的。导致主要构建或其他开发人员的构建中断,会更糟糕。找到平衡很难 - 除非有人是决策者,花一些时间阅读其他团队成员编写的测试代码。

有些人采用测试边缘情况的方法,并假设主要功能将通过使用得到解决。考虑到getter / setter,我想要一个模型类,对这些方法进行一些测试,可能会测试数据库列类型范围。这至少告诉我网络没问题,可以建立数据库连接,我可以访问写入存在的表等。页面来去匆匆,所以不要认为页面加载是实际的替代单元测试。 (测试效率方面的注意事项 - 如果基于文件更新时间戳(自动测试)进行自动测试,该测试将无法运行,并且您希望尽快知道)

我希望有更好的质量测试,而不是全面覆盖。但我还想要一个自动化工具来指出未经测试的内容。如果它没有经过测试,我认为它已经坏了。当您发现失败时,添加测试,即使它是简单的代码。

如果要自动化测试,运行所需的时间并不重要。每次运行测试代码时都会受益 - 此时,您知道代码的最低功能正在运行,并且您可以了解测试功能在一段时间内的可靠性。

100%的覆盖范围不应该是您的目标 - 良好的测试应该是。认为正则表达式的单个测试完成任何事情都会产生误导。我宁愿没有测试而不是一个,因为我的自动报道报告提醒我RE是不可靠的。

答案 2 :(得分:6)

唯一绝对的规则是测试应该具有成本效益。

任何实现这一目标的实用指南都会引起争议,但这里有一些建议可以避免通常会浪费的测试,或者弊大于利。

单元

  • 不要直接测试私有方法,只能通过调用它们的公共方法间接评估它们的效果。
  • 不测试内部状态
  • 只测试非平凡的方法,其中不同的上下文可能会得到不同的结果(计算,连接,正则表达式,分支......)
  • 不评估您不关心的内容,例如完整复制一些消息或API返回的复杂数据结构的无用部分...
  • 存储单元测试中的所有内容,它们被称为单元测试,因为您只测试一个类,而不是它的协作者。使用存根/间谍,您可以测试发送它们的消息,而无需测试其内部逻辑。
  • 将私有嵌套类视为私有方法

集成

  • 不要尝试在集成测试中测试所有组合。这就是单元测试的用途。只需测试快乐路径或最常见的情况。
  • 除非你真的是BDD
  • ,否则不要使用黄瓜
  • 集成测试并不总是需要在浏览器中运行。要测试性能下降较少的更多案例,您可以让一些集成测试直接与模型类交互。
  • 不要测试你不拥有的内容。集成测试应该期望第三方依赖项能够完成它们的工作,但不能替代它们自己的测试套件。

控制器

  • 在控制器测试中,仅测试控制器逻辑:重定向,身份验证,权限,HTTP状态。存根业务逻辑。考虑过滤器等,如单元测试中的私有方法,仅通过公共控制器操作进行测试。

其他

  • 不要编写路由测试,除非您正在编写API,否则对于集成测试尚未涵盖的端点。
  • 不要编写视图测试。您应该能够在不破坏测试的情况下更改副本或HTML类。只需评估关键视图元素,作为浏览器内集成测试的一部分。
  • 测试您的客户端JS ,特别是如果它拥有某些应用程序逻辑。所有这些规则也适用于JS测试。

忽略关键业务的任何规则,或者当某些事情真正中断时(没有人想解释他们的老板/用户为什么同样的错误发生两次,这就是为什么你应该在修复时至少写回归测试的原因)缺陷)。

详情请见that post

答案 3 :(得分:5)

通过为此方法编写一个或两个单元测试所获得的主要好处是回归测试。如果在将来某个时候某些事情发生了变化,会对这种方法造成负面影响,那么你就能够抓住它。

这是否值得努力最终取决于你。

通过查看它可以看到的第二个好处是测试边缘情况,例如,如果last_name""nil,它应该做什么。这可以揭示出意外的行为。

(即如果last_namenilfirst_name"John",则会full_name => "John "

同样,成本与收益最终取决于您。

答案 4 :(得分:1)

对于生成的代码,不,没有必要在那里进行测试覆盖,因为正如你所说,你没有写它。如果出现问题,则超出了测试范围,应该将重点放在项目上。同样,您可能不需要显式测试您使用的任何库。

对于你的特定方法,它看起来就像是一个setter(自从我完成Ruby on Rails之后就已经有点了) - 测试该方法将测试语言功能。如果您要更改值或生成输出,那么您应该进行测试。但是,如果您只是设置值或返回没有计算或逻辑的东西,我不认为让测试覆盖这些方法的好处就好像它们是错误的,您应该能够在目视检查或问题中检测到问题是一种语言缺陷。

就其他方法而言,如果你编写它们,你应该对它们进行测试。在测试驱动开发中,这是必不可少的,因为在方法之前存在特定方法的测试,并且您编写了使测试通过的方法。如果你没有先编写测试,那么如果这种方法发生变化,你至少可以获得一些简单的测试。