Ruby on Rails Tutorial の 3.6.2 - 3.6.3 に記載されているテストの自動化をほぼそのまま試しています。だいぶ説明を端折っているので原文を読んだほうが良いとおもいますが作業メモとしてここに残しておきます。
Learn Web Development with the Ruby on Rails Tutorial | Static Pages
一々 bundle exec rspec hogehoge.rb とかするのだるいから自動でしましょうってことでしょうか。Guard を使用して rails のテストを自動化してみます。
Guard の設定
Gemfile 編集して guard を使うように書き換えます
group :development, :test do
gem 'sqlite3'
gem 'rspec-rails', '2.13.0'
gem 'guard-rspec', '2.5.0'
end<
書き換えたらインストールします。
$ bundle install
インストールがうまくいったら Guard の初期化を行います。
$ bundle exec guard init rspec
INFO - Writing new Guardfile to /home/ryomatsu/example/rortest/demo_app/Guardfile
INFO - rspec guard added to Guardfile, feel free to edit it
初期化したら Guardfile を編集します。
guard 'rspec', all_after_pass: false do
...
# Custom Rails Tutorial specs
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) do |m|
["spec/routing/#{m[1]}_routing_spec.rb",
"spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb",
"spec/acceptance/#{m[1]}_spec.rb",
(m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
"spec/requests/#{m[1].singularize}_pages_spec.rb")]
end
watch(%r{^app/views/(.+)/}) do |m|
(m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
"spec/requests/#{m[1].singularize}_pages_spec.rb")
end
watch(%r{^app/controllers/sessions_controller\.rb$}) do |m|
"spec/requests/authentication_pages_spec.rb"
end
...
:all_after_pass => false というのはテストにパスしたときに全部のテストを実行しない、というオプションの指定。全部テストしてたら結構時間かかるのでオフにしておきます。
書き換えたら実行してみる。
$ bundle exec guard
19:38:04 - INFO - Guard uses Tmux to send notifications.
19:38:04 - INFO - Guard uses TerminalTitle to send notifications.
19:38:04 - INFO - Guard::RSpec is running
19:38:04 - INFO - Running all specs
......
Finished in 0.49647 seconds
6 examples, 0 failures
ちゃんと動いてるようです。
Spork でテストのスピードアップ
bundle exec rspec したとき結構時間かかるヨネーってことで Spork を使ってテストを高速に走らすようにします。
Gemfile を編集して Spork を使用するように修正します。
group :development, :test do
gem 'sqlite3'
gem 'rspec-rails', '2.13.0'
gem 'guard-rspec', '2.5.0'
gem 'spork-rails', github: 'railstutorial/spork-rails'
gem 'guard-spork', '1.5.0'
gem 'childprocess', '0.3.6'
end
書き換えたら install
$ bundle install
そして実行, spork の設定を行います。
$ bundle exec spork --bootstrap
Using RSpec, Rails
Bootstrapping /home/ryomatsu/example/rortest/demo_app/spec/spec_helper.rb.
Done. Edit /home/ryomatsu/example/rortest/demo_app/spec/spec_helper.rb now with your favorite text editor and follow the instructions.
spork 無いとかいわれたら Gemfile に gem 'spork' とか書いて bundle install しなおすと動いたりします。
ちゃんと動いたら spec/spec_helper.rb を 編集します。Spork.prefork ブロックを以下のようにします。
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# 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
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include Capybara::DSL
end
end
これで準備ができました。
spork の実行
spork を実行する前に、spork を使わないときの実行時間を測っておいて、どのくらい高速化できるのかを調べれるようにします。
$ time bundle exec rspec spec/requests/static_pages_spec.rb
......
Finished in 0.21145 seconds
6 examples, 0 failures
Randomized with seed 65477
bundle exec rspec spec/requests/static_pages_spec.rb
5.94s user 0.35s system 99% cpu 6.329 total
5.94s ほどかかってますね。
次は spork を使ってみます。
$ bundle exec spork
Using RSpec, Rails
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!
$ time bundle exec rspec spec/requests/static_pages_spec.rb --drb
......
Finished in 0.26917 seconds
6 examples, 0 failures
Randomized with seed 1167
bundle exec rspec spec/requests/static_pages_spec.rb --drb
1.90s user 0.10s system 80% cpu 2.494 total
3倍ほど早くなりました。
Guard と Spork を併用する
guard で spork を使うように設定します。まず初期化。
$ bundle exec guard init spork
INFO - spork guard added to Guardfile, feel free to edit it
そして Guardfile を spork を使用するように編集します。
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')
watch('Gemfile.lock')
watch('spec/spec_helper.rb') { :rspec }
watch('test/test_helper.rb') { :test_unit }
watch(%r{features/support/}) { :cucumber }
end
編集したら guard を実行しましょう。
$ bundle exec guard
INFO - Guard uses Tmux to send notifications.
INFO - Guard uses TerminalTitle to send notifications.
INFO - Starting Spork for RSpec, Test::Unit
Using RSpec, Rails
Preloading Rails environment
Couldn't find a supported test framework that begins with 'testunit'
Supported test frameworks:
( ) Cucumber
(*) RSpec
Legend: ( ) - not detected in project (*) - detected
Loading Spork.prefork block...
Spork is ready and listening on 8989!
これで Spork と Guard を使用した自動テスト環境が構築できました。が、なんだか Spork 自体の起動に失敗したとかいうエラー出たり出なかったりします。なんなんでしょう。ほっといたら直ったけど。
とりあえずこの状態で rails プロジェクト内のファイルを編集するとテストが実行されて、テストに失敗したら赤くなったり成功したら緑になったりします。tmux との連携もされてて良いですね。