【问题标题】:What not to test in Rails?什么不能在 Rails 中测试?
【发布时间】:2010-09-02 18:28:53
【问题描述】:

我已经编写测试有一段时间了,现在我开始掌握事情的窍门。但是我有一些关于真正需要多少测试覆盖率的问题。共识似乎很明确:更多的报道总是更好。但是,至少从初学者的角度来看,我想知道这是不是真的。

以这个完全普通的控制器动作为例:

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 真的需要单元测试吗?

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

但是,就像我说的,我几乎不是专业的测试人员。我不一定提倡减少测试覆盖率。相反,我正在寻找一些专家的建议。编写如此简单的测试真的有充分的理由吗?

【问题讨论】:

标签: ruby-on-rails rspec testing


【解决方案1】:

我在这方面的经验是,你不应该浪费时间为琐碎的代码编写测试,除非你有很多复杂的东西依赖于正确性的琐碎。一方面,我认为测试像 getter 和 setter 这样的东西完全是浪费时间,但我敢肯定会有不止一个覆盖爱好者愿意在这方面反对我。

对我来说,测试有助于三件事:

  1. 他们保证完整的旧功能如果我可以检查 我放的新东西没有坏掉 通过运行测试我的旧东西,它是 一件好事。

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

  3. 它们是我工作的文档 记录在案。但是,如果您同意 对我来说,代码中的 cmets 是 魔鬼的工作,有清晰和 简洁的单元测试让你 了解正确的行为 某事是,是(再次)必须的。

任何我确定不会破坏的东西,或者我觉得不需要记录的东西,我根本不会浪费时间进行测试。那么,即使没有单元测试,您生成的控制器和模型方法也都很好。

【讨论】:

    【解决方案2】:

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

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

    单位

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

    集成

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

    控制器

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

    其他

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

    忽略任何针对业务关键性内容的规则,或者当某些事情实际发生故障时(没有人愿意向他们的老板/用户解释为什么相同的错误会发生两次,这就是为什么您可能应该在修复一个问题时至少编写回归测试错误)。

    that post上查看更多详情。

    【讨论】:

    • “那个帖子” - 链接断开。
    【解决方案3】:

    更多的覆盖范围对代码质量更好——但它的成本更高。这里有一个滑动比例,如果你正在编写人造心脏,你需要更多的测试。你预付的钱越少,你以后支付的可能性就越大,也许是痛苦的。

    在示例中,全名,为什么要在其之间放置一个空格,并按名字排序,然后按姓氏排序——这有关系吗?如果稍后要求您按姓氏排序,是否可以交换顺序并添加逗号?如果姓氏是两个词怎么办——额外的空间会影响事情吗?也许您还有其他人正在解析的 xml 提要?如果您不确定要测试什么,对于一个简单的未记录函数,不妨考虑方法名称所暗示的功能。

    我认为贵公司的文化也很重要。如果你做的比别人多,那你真的是在浪费时间。如果主要内容有问题,那么拥有经过良好测试的页脚也无济于事。导致主构建或其他开发人员的构建中断,会更糟。找到平衡很难——除非一个人是决定者,否则花一些时间阅读其他团队成员编写的测试代码。

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

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

    如果您要使测试自动化,那么运行多长时间并不重要。每次运行测试代码时,您都会受益——此时,您知道代码的最低限度的功能正在运行,并且随着时间的推移,您会了解测试功能的可靠性。

    100% 的覆盖率不应该是您的目标——良好的测试应该是。认为一个正则表达式的测试就能完成任何事情是一种误导。我宁愿没有测试也不愿测试,因为我的自动覆盖率报告提醒我 RE 不可靠。

    【讨论】:

      【解决方案4】:

      为此方法编写一两个单元测试的主要好处是回归测试。如果在未来的某个时候,某些改变对这种方法产生了负面影响,你将能够抓住它。

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

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

      (即如果last_namenil,而first_name"John",你会得到full_name => "John "

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

      【讨论】:

        【解决方案5】:

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

        对于您的特定方法,它看起来相当于一个 setter(自从我完成 Ruby on Rails 以来已经有一段时间了) - 测试该方法将测试语言特性。如果您正在更改值或生成输出,那么您应该进行测试。但是,如果您只是设置值或返回没有计算或逻辑的东西,我看不出让测试覆盖这些方法的好处,就好像它们是错误的一样,您应该能够在视觉检查中发现问题或问题是语言缺陷。

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

        【讨论】:

          猜你喜欢
          • 2011-11-29
          • 1970-01-01
          • 1970-01-01
          • 2010-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多