Rails / RSpec テスト書いたことない メンドクサイ(n´Д`)という時のチートシート
テストを書かないようになってしまっていた。
大きなアプリケーションではないし一人で作ってるし… まぁいいか的な。
ただ、コードの量が増えていくにつれやっぱりちょっと辛い。
書き方すっかり忘れたので、RSpec再入門。
環境
Vagrant + CentOS (centos64box)
Ruby 2.2.1
Rails 4.1.1
最終的なGemfile(テスト関係だけ)
テスト用のDBの設定をお忘れなく。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
gem 'pg'
group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'guard-rspec'
gem 'spring-commands-rspec'
end
group :test do
gem 'faker'
gem 'capybara'
gem 'database_cleaner'
gem 'poltergeist'
gem 'shoulda-matchers'
end
準備
1
$ rails g rspec:install
.rspecファイルに --format documentation
を追加すると表示結果がキレイになる。
デフォルトのテストフレームワークをRspecにするのと、
rails g
した時に作られるファイルを制御。
config/application.rb
1
2
3
4
5
6
7
8
9
10
config.generators do |g|
g.test_framework :rspec,
fixtures: true,
view_specs: false,
helper_specs: false,
routing_specs: false,
controller_specs: true,
request_specs: false
g.fixture_replacement :factory_girl, dir: "spec/factories"
end
FactoryGirl
使う際に便利な設定をしておく。
FactoryGirl.create(:contact)
の代わりに
create(:contact)
と書けるようになる。
spec/rails_helper.rb
ruby
1
2
3
RSpec.configuredo|config|
config.include FactoryGirl::Syntax::Methods
end
コールバックを使うと手間が省ける。
Fakerも便利。
spec/factories/mobel.rb
ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
FactoryGirl.define do
factory :model do
firstname { Faker::Name.first_name }
lastname { Faker::Name.last_name }
email { Faker::Internet.email }
after(:build) do |mobel|
[:type1, :type2, :type2].each do |type|
model.other_models << FactoryGirl.build(:other_model, type: type)
end
end
end
end
マクロ
何回も使う処理はマクロにしてしまおう。
spec/supports
フォルダを作って
login_macros.rb
に定義されたマクロを読み込む設定。
spec/rails_helper.rb
ruby
1
2
3
4
RSpec.configure do |config|
Dir[Rails.root.join("spec/supports/**/*.rb")].each{ |f| require f }
config.include LoginMacros
end
カスタムマッチャー
supports/matchers/require_login.rb
定義すると expect(response).to require_login
とか書ける。
1ファイルにつき1マッチャなので注意。
ruby
1
2
3
4
5
RSpec::Matchers.define:require_login do |expected|
match do |actual|
expect(actual).to .....
end
end
フィーチャースペック
features/....rb
にファイルを追加。
Javascriptが必要な場合は js: true
を付ける。
ruby
1
2
3
4
5
feature "Something" do
scenario "do something", js: true do
.....
end
end
フィーチャースペックにはJavascriptはほぼ必須だろうから、
PhantomJSをインストールする。
本ではSeleniumだけど、結構手間がかかるので PhantomJS
がいい。
これならサクっといきます。
Seleniumについては前に書いてみたのもある。
参考
PhantomJSをCentOS6にインストール - Qiita
初心者大歓迎!RSpec 3でドラッグアンドドロップ機能をテストする方法(スクリーンキャスト付き) - Qiita
database_cleaner も入れておく。
database strategies
てなに?
transaction
と truncation
何が違うの?というのは、下記が参考になった。
ruby - Difference between truncation, transaction and deletion database strategies - Stack Overflow
Gemfile
1
2
gem 'poltergeist'
gem "database_cleaner"
spec/rails_helper.rb
ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'capybara/poltergeist'
require 'database_cleaner'
RSpec.configure do |config|
config.use_transactional_fixtures = false
# Js driver
Capybara.javascript_driver = :poltergeist
# Cleaner
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
ちなみに、
find_button('Close').click などの待ち時間は下記のように設定できる。
ruby
1
Capybara.default_wait_time = 15
Shoulda
便利なマッチャ thoughtbot/shoulda-matchers 。
これがあれば自分で書くコードが少なくなる。
Gemfile
1
gem 'shoulda-matchers'
こんな感じでね。
ruby
1
2
subject { Contact.new }
it { should validate_presence_of(:firstname).with_message("名前は必須です") }
Guard
ファイルを変更した時に自動的にテストを走らせる。
Gemfile
1
2
3
group :development, :test do
gem 'guard-rspec'
end
このコマンドでGuardfileが作成される。
必要に応じてオプションを変更/追加する。
1
$ bundle exec guard init rspec
Guardfile
ruby
1
2
3
guard :rspec, cmd: "spring rspec --color --format documentation", all_on_start: false do
...
end
notification: false
all_on_start: false
all_on_pass: false
など。
Vagrant のローカル開発環境でやっていて、
Macの Sublime Text でファイルを編集しているんだけども、
ファイル変更時に Guard が走らなかった。
Guard起動時にオプションを渡すことで解決。
1
$ bundle exec guard -p -l 10
参考
Vagrant + Guard 環境でファイル変更が検知されない - Qiita
Spring
テストの実行が速くなるよ。
Gemfile
1
2
3
group :development, :test do
gem 'spring-commands-rspec'
end
1
2
$ bundle exec spring binstub rspec
$ bin/spring stop
Guardfileにspringを指定
ruby
1
2
3
guard :rspec, cmd: "spring rspec --color --format documentation", all_on_start: false do
...
end
そのほか便利な機能
タグ機能
1
2
3
it "processes the deal", focus: true do
# example
end
rspec --tag focus
で focus: true
のテストだけ実行。
あらかじめ設定しておくことも出来る。
spec/rails_helper.rb
ruby
1
2
3
4
RSpec.configure do |config|
config.filter_run focus: true
config.filter_run_excluding slow: true
end
メール送信をテスト
bmabey/email-specというGemが便利。
ファイルのアップロードのテスト
spec/factories に保存しているファイルを使う。
時間をテスト
travisjeffery/timecop が便利。
外部サービスをテスト*
vcr/vcr が便利。
テストはFeature Specから書くといいそうな。
Outside-inだと。
今回読んだ本
Everyday Rails - RSpecによるRailsテスト入門
前にお世話になった Ruby on Rails チュートリアル:実例を使って Rails を学ぼう と
似たような感覚で読み進められる。RSpec + Rails にフォーカスしてるのでありがたい。
2日間で一気に読んだ + 実験したけど、
明日から自分のサービスのテストが書き始められそう。
まだメンドクサイ(n´Д`)という気持ちはあるけどね…。
TDDには程遠いけど、書いていこう。