【问题标题】:Should rails units tests hit database or not?Rails 单元测试是否应该命中数据库?
【发布时间】:2010-11-25 13:57:13
【问题描述】:

我一直在为我的 rails 应用程序编写测试。我使用 TestUnit 进行单元测试和功能测试。我也使用 cucumber 进行 GUI 测试。

但我发现http://www.dcmanges.com/blog/rails-unit-record-test-without-the-database 说单元测试最好不要命中数据库。

我同意访问数据库需要相当长的时间。我已经使用 spork 来减少环境负荷。

在测试 Rails 应用时,最佳实践是什么?

【问题讨论】:

    标签: ruby-on-rails unit-testing testing


    【解决方案1】:

    这是您不应该过于关注名称的情况之一。 Rails 将使用 ActiveRecord 模型的测试称为“单元”测试,主要是因为它们是框架直接支持的最低级别的测试。根据测试知识,我承认我倾向于相当一致地分裂,单元测试不应该依赖于被测单元的外部;这意味着诸如持久性机制之类的东西,即数据库。

    也就是说,在没有数据库的情况下测试任何复杂的 ActiveRecord 模型很快就会让你想吃掉你的手。 Rails 假设您使用数据库进行测试;这就是框架的编写方式。您可以尝试将所有内容存根,但最终会失败,因为您最终会在 ActiveRecord 关联的内部搞乱(不适合胆小的人)。您可以尝试将所有与持久性无关的代码提取到单独的模块中,在没有数据库的情况下进行测试,但您会产生很多不必要的复杂性。

    不要试图与框架抗争。 ActiveRecord 和 ActionController 在生产和测试中都有非常具体的预期使用模式。毕竟,Rails 是关于约定的。如果您遵循使用模式,那么您将做的工作少得多,并且比您为了坚持单元测试理想而与惯例抗争的情况要少得多。如果它让您感觉更好,请将您的 ActiveRecord 测试视为“模型”测试,将您的功能测试视为“控制器”测试(这是 rspec 使用的术语,顺便说一句)。

    话虽如此,您不应在模型测试(或规范)中不必要地访问数据库。一些验证,例如唯一性,需要数据库,但大多数不需要。许多与创建/保存回调和关联相关的操作都需要数据库,但其他操作不需要。请注意您正在调用的操作正在执行的操作。

    【讨论】:

    • 我完全同意这个答案。我只想补充一点,即努力使用 RSpec 编写的系统或集成测试(我的大部分控制器和一半模型测试都是集成测试)来测试所有功能。当我觉得逻辑相当复杂并且集成测试没有提供足够的覆盖率时,我会使用额外的单元测试。
    【解决方案2】:

    单元测试不应该命中数据库。如果正确的数据可用(无论数据来自何处),他们应该测试方法是否按预期运行。因此,您应该根据需要进行存根/模拟,以确保每个单元测试都是独立的。

    但是集成测试(例如,您可能使用 Cucumber 编写)应该将整个 MVC 堆栈捆绑在一起,并且没有理由不访问数据库

    【讨论】:

    • 所以你的意思是说,如果一个方法(正在测试的)有诸如AnotherModel.find_by_name()之类的调用,那么find方法也应该被存根?
    • 尽可能多,是的。如果AnotherModel.find_by_name(...) 不起作用,则不应影响此模型的单元测试
    【解决方案3】:

    使用“命中数据库的单元测试”来测试模型是“Rails 方式”的论点与说“每个人都从桥上跳下来,也许我应该?”是一回事。

    应该认真分析您遵循的每个 Rails 约定,因为事后看来,“单一的 Rails 应用程序”,如果他们遵循这个建议,他们将拥有 100 多个带有集成测试的模型。即使您将规范标记为慢速和快速,您也没有围绕“快速”类别中的模型进行单元测试(除非您也编写了它们,在这种情况下,您可能正在测试太多)。

    副作用:需要一个小时的缓慢单元测试套件。假设您将每个方法都保留在模型中,而不是将其抽象到不同的类中,那么您将处于一个更加痛苦的世界,因为您还需要为它们编写集成测试。

    我知道无论你做什么,集成测试仍然会很慢,但你可以克服缓慢的唯一方法就是巧妙地编写它们。

    我正在尝试编写从 HTTP 请求到数据库的“请求规范”。并将它们用作我的“功能测试”。我编写的每个类,无论是服务、模型还是你有的东西,都有围绕它们的公共方法的单元测试(显然是存根 DB)。

    【讨论】:

      【解决方案4】:

      使用快速的内存数据库进行单元测试。如果您想测试“如果有正确的数据可用,方法是否按预期运行”,最好使用与您的真实数据集非常相似的数据集。内存数据库可以包含非常小或相当大的数据集,具体取决于您的需要。 HSQLDB 受 ruby​​-on-rails 支持,常用于单元测试。

      【讨论】:

      • 我很久以前就试过了,我的问题是:a) 内存数据库不太可能设置相同的触发器/SP/etc。 b) 它很慢,比运行关闭(但不是本地)的专用开发数据库慢很多。
      • HSQLDB 现在支持触发器/SP/等。但可能存在语法差异。当目标是 Oracle、DB2 等(速度很快)时,许多开发人员使用 HSQLDB 进行测试。请参阅此示例:sourceforge.net/tracker/…
      • 我们已经多次使用内存数据库对运行测试进行基准测试,事实上内存数据库在测试方面并没有更快。听起来不错,每个人都认为会是这样,但数字不会说谎。
      • 数字不会说谎。见这里:polepos.sourceforge.net/results/html/index.html
      • 我实际上并不确定我来自哪里或我做了什么才能到达此页面(可怕!),但我只想为在这里绊倒的其他人添加我的 +1思考内存数据库加速测试。我们试过了,它肯定不会更快。改进您的设置/拆卸逻辑将为您带来更好的收益(即 TRUNCATE 表,不要重建架构;如果可以,将您截断的内容限制为仅在测试期间使用的那些表...棘手)。
      猜你喜欢
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 2016-06-08
      相关资源
      最近更新 更多