[Ruby on Rails 3, Ruby on Rails 4] RSpec/Capybara: Spork でテストを高速化する

つづき。
「Ruby on Rails チュートリアル」をさわってみます。

テストが開始されるまで時間がかかるのは、Railsの環境全体を読み込み直す必要があるから。
Spork は、これを解決することでテストの速度を向上させるとのこと。

Contents

Gemfile

group :development, :test do
  gem 'sqlite3', '~> 1.3.5'
  gem 'rspec-rails', '~> 2.11.0'
  gem 'guard-rspec'
  gem 'guard-spork'
  gem 'childprocess'
  gem 'spork'
end

インストール

% bundle install
% bundle exec spork --bootstrap
Using RSpec
Bootstrapping /Users/****/projects/sample_app/spec/spec_helper.rb.
Done. Edit /Users/****/projects/sample_app/spec/spec_helper.rb now with your favorite text editor and follow the instructions.

spec/spec_helper.rb

指示された spec/spec_helper.rb を設定します。

% subl spec/spec_helper.rb

ファイルを確認すると、Spork によって、2つのメソッドが追加されていました。

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it take effect.
end
Spork.each_run do
  # This code will be run each time you run your specs.
end

さらにファイルの中程から最後をみると、rspecの記述があるのでこれをコメントアウトして、Spork.prefork 内にコピーしてみました。

Spork.prefork do
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'rspec/autorun'
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
  RSpec.configure do |config|
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = true
    config.infer_base_class_for_anonymous_controllers = false
    config.order = "random"
  end
end

Spork を起動する

以下でサーバが起動します。

% bundle exec spork
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!

速度の比較

–drb (“distributed Ruby” の略) オプションを追加することで、Spoke が利用されるので、速度を比較してみる。

% time bundle exec rspec spec/requests/static_pages_spec.rb
........
Finished in 0.35374 seconds
8 examples, 0 failures
Randomized with seed 44534
bundle exec rspec spec/requests/static_pages_spec.rb  3.24s user 0.74s system 97% cpu 4.085 total
% time bundle exec rspec spec/requests/static_pages_spec.rb --drb
........
Finished in 0.38702 seconds
8 examples, 0 failures
Randomized with seed 48212
bundle exec rspec spec/requests/static_pages_spec.rb --drb  0.86s user 0.14s system 63% cpu 1.579 total

CPU使用率が違うようですが、半分以下になっているようです。

.rspec

Spork を標準で使えるよう、RSpecの設定に追加する。

% subl .rspec
--color
--drb

GuardにSporkを導入する

GuardfileにSporkを追加します。

% bundle exec guard init spork
23:37:33 - INFO - spork guard added to Guardfile, feel free to edit it
% subl Guardfile

追加された以下のセクションを、RSpecセクションの上に移動します。

guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
  watch('config/application.rb')
  watch('config/environment.rb')
  watch('config/environments/test.rb')
  watch(%r{^config/initializers/.+\.rb$})
  watch('Gemfile.lock')
  watch('spec/spec_helper.rb') { :rspec }
  watch('test/test_helper.rb') { :test_unit }
  watch(%r{features/support/}) { :cucumber }
end

さらにRSpecセクションに、, :cli => '--drb'を追加します。

guard 'rspec', :version => 2, :all_after_pass => false, :cli => '--drb' do

GuardとSporkを同時に起動する

guardコマンドでGuardとSporkを同時に起動します。

% bundle exec guard
23:49:58 - INFO - DEPRECATION WARNING: The :version option is deprecated. Only RSpec 2 is now supported.
23:49:58 - INFO - Guard is using TerminalNotifier to send notifications.
23:49:58 - INFO - Guard is using TerminalTitle to send notifications.
23:49:59 - INFO - Starting Spork for RSpec
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!
23:50:05 - INFO - Spork server for RSpec successfully started
23:50:05 - INFO - Guard::RSpec is running
23:50:05 - INFO - Running all specs
Running tests with args ["--drb", "-f", "progress", "-r", "/Users/****/projects/sample_app/vendor/bundle/ruby/2.0.0/gems/guard-rspec-2.5.4/lib/guard/rspec/formatter.rb", "-f", "Guard::RSpec::Formatter", "--failure-exit-code", "2", "spec"]...
........
Finished in 0.41932 seconds
8 examples, 0 failures
Randomized with seed 28763
Done.
23:50:08 - INFO - Guard is now watching at '/Users/****/projects/sample_app'
[1] guard(main)>

補遺

preforkで読み込むファイル (たとえばroutes.rb) が変更された場合、Sporkサーバーを再起動して新しいRailsの環境を再度読み込む必要があります。パスするはずのテストが失敗した場合は、Ctrl-CでSporkサーバーを停止して再起動してください。

Spoke の設定

Spork.each_run do
  FactoryGirl.reload
end