如何更快地在RoR上运行测试?

时间:2011-07-05 13:44:19

标签: ruby-on-rails testing

我正在使用Ruby on Rails 3并编写测试,但速度太慢了。 是否有一些好的配置或工具可以加快速度?

5 个答案:

答案 0 :(得分:4)

除非您需要,否则最大的速度增益可能来自于小心不要打到数据库。模拟对象而不是从数据库中获取它们和/或(例如,如果您使用的是工厂女孩)尽可能使用Factory.build(:stuff)而不是Factory(:stuff)。只有当你这样做时,才应该开始尝试使用spork进一步优化

更新: 就我个人而言,我也开始认为你不应该对你的测试速度感到不知所措。更快更好,但随着应用程序的增长,测试套件将会增长,无论你多么小心,它最终会变得比你想要的慢。我将越来越多地依赖于测试更改代码并在后台工作的autotest gem(guard-rspec做了类似的工作)。当您的应用程序达到1000次测试时,您不希望每次进行更改时都等待整个套件完成,无论测试运行得多么快。

答案 1 :(得分:2)

正如@eml所说,如果你正在使用RSpec,你可以使用Spork。这基本上会激发环境(这是缓慢的部分)然后保持它,每次运行你的规格时都会分叉。

对于“环境始终加载”问题的更一般的解决方案,可以安装rails-sh并在shell中运行测试。

旁注:随着需求时间的优化,Ruby 1.9.3应该稍微缓解这个问题。

答案 2 :(得分:2)

恕我直言,测试的主要减缓部分是灯具的默认配置。如果您的配置是(test/test_helper.rb):

class ActiveSupport::TestCase
  self.use_transactional_fixtures = false
  self.pre_loaded_fixtures = false
  self.use_instantiated_fixtures  = true

然后在每个测试方法之前,从旧数据中清除测试数据库,填充所有表,将所有记录读入内存。

如果您将设置更改为相反的设置:

class ActiveSupport::TestCase
  self.use_transactional_fixtures = true
  self.pre_loaded_fixtures = true
  self.use_instantiated_fixtures  = false

然后只为每个测试文件重新创建一次数据库,并且只加载每个测试方法中真正需要的记录。

取决于测试数据集的大小,您是否发现测试数据库创建的时间可以接受。当我有一些非常大的测试数据集时,我在整个测试套件之前只加载了一次灯具,但是那个项目在Rails 1中已经很好了,我已经对其进行了大量修改,所以我不知道怎么做在Rails 3中(至少直到问题在一些新项目中开始变得痛苦;)。

关于测试是否应该访问数据库存在无休止的讨论。如果您认为他们应该(因为数据库合作也应该进行测试),那么您可以检查设置这些参数是否有助于您(或任何人阅读这些答案)。

答案 3 :(得分:0)

我建议使用SporkGuard,这两者都可以与RSpec完美配合。

Spork可以帮助您更快地运行测试, http://railscasts.com/episodes/285-spork

Guard可以帮助您自动运行测试。 http://railscasts.com/episodes/264-guard

答案 4 :(得分:0)

尝试开发,以便无需加载整个Rails应用程序框架即可执行大多数测试。在你的规范助手中,如果只执行快速测试,请跳过加载环境或rpec / rails,如......

# /spec/spec_helper.rb
if RSpec.configuration.inclusion_filter[:fast]
  # Setup required for fast tests in particular (if any)
  # ...
else
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'

  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
end

RSpec.configure do |config|
  # ...

  unless RSpec.configuration.inclusion_filter[:fast]
    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = true
  end
end

要将测试标记为“快速”,请将, :fast => true选项添加到其it来电或周围describe来电。

要仅运行快速测试,请从命令shell执行rspec --tag fast

很难弄清楚如何构建代码,以便测试可以与Rails分开运行(当然,您仍然希望进行不单独运行的功能和集成测试)。

我的库中的一个技巧是避免直接在ActiveRecord模型或其他类似的代码上编写代码,而更喜欢在mixin模块上编写代码。您可以通过将Subject定义为由该模块扩展的对象来测试mixin模块...

describe 'MyModule', :fast => true
  subject{ Object.new.tap{|o| o.extend MyModule} }

  it 'does something' do
    # ...
  end
end