Rails
RSpec

基礎からやり直す Rails RSpec

RSpecについてちゃんと学習してこなかったので、今回しっかり腰を据えて復習しました。

使った教材は次の3冊です。

以下では、そこで学んだことを整理します。


RSpecのテスト設計

RSpec の基本的なディレクトリ構造は公式ドキュメントで示されています。

公式ドキュメント

基本的には次のような構成になります。

spec

├── factories # テスト生成
├── features # インテグレーション/アクセプタンス
├── helpers # ユニット
├── models # ユニット
├── rails_helper.rb # 設定ファイル
├── requests # インテグレーション/アクセプタンス
├── services # ユニット
└── spec_helper.rb # 設定ファイル

最近は Controller specs の代わりに、より広範囲をテストする Request specs が用いられるのが主流です(両者の違いについてはこちら)。

RSpec チームからも Request specs を使うことが推奨されています(2016年:詳細はこちら)。


For new Rails apps: we don't recommend adding the rails-controller-testing gem to your application. The official recommendation of the Rails team and the RSpec core team is to write request specs instead.


また、ビジネスロジックをサービスオブジェクトに切り出す場合などは、他のユニットテストと同様に、rspec/services 配下にテストコードを書いていきます。


RSpecの初期設定

新規にRailsアプリを作る場合の初期設定について整理します。


gem インストール

まずは RSpec のインストールです。


Gemfile

group :development, :test do

gem 'rspec-rails', '~> 3.6.0'
end

$ bundle install

次のコマンドで RSpec のファイルがもろもろ生成されます。

$ rails g rspec:install


.rspec

好みですが、見やすいフォーマットで表示させるために .rspec ファイルを次のように編集します。


.rspec

--require spec_helper

--format documentation


Spring

Springを使ってテスト環境の立ち上げ速度を上げます。

gem をインストールします。


Gemfile

group :development do

gem 'spring-commands-rspec'
end

$ bundle install 

binstub を使えるようにします。

$ bundle exec spring binstub rspec

これで次のコマンドで RSpec を実行できるようになりました。

$ bin/rspec


config/application.rb

rails generate コマンドで自動生成されるファイル種類を調整します。


config/application.rb

config.generators do |g|

g.test_framework :rspec,
view_specs: false,
helper_specs: false,
routing_specs: false
end


spec/rails_helper.rb

次の行のコメントアウトを取り、spec/support 配下にあるRSpecの設定ファイルが読み込まれるようにします。


spec/rails_helper.rb

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



FactoryBot

テストデータ生成用のツール FactoryBot をインストールします。


Gemfile

group :development, :test do

gem 'factory_bot_rails', '~> 4.10.0'
end

$ bundle install

FactoryBotのコードを spec/factories 配下に書いていきます。

テストコードから FactoryBot を省略してデータ生成できるように設定ファイルを追加します。


spec/support/factory_bot.rb

RSpec.configure do |config|

config.include FactoryBot::Syntax::Methods
end

これで FactoryBot.create(:user) ではなく、 create(:user) と書くだけでデータ生成できるようになりました。


Devise用の設定

Requset specs でログイン周りのDeviseヘルパーが利用できるように、設定ファイルを追加します。


spec/support/request_spec_helper.rb

module RequestSpecHelper

include Warden::Test::Helpers

def self.included(base)
base.before(:each) { Warden.test_mode! }
base.after(:each) { Warden.test_reset! }
end

def sign_in(resource)
login_as(resource, scope: warden_scope(resource))
end

def sign_out(resource)
logout(warden_scope(resource))
end

private

def warden_scope(resource)
resource.class.name.underscore.to_sym
end
end

RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include RequestSpecHelper, type: :request
end



Capybara

Feature specs 用のツールとして Capybara をインストールします。


Gemfile

group :test do

gem 'capybara', '~> 2.15.4'
gem 'webdrivers'
gem 'launchy', '~> 2.4.3'
end

webdrivers は、JSの挙動を含めたテストをする際に必要です。launchy は Feature specs のデバッグツールで、テストが失敗した場合にブラウザがどのような状態だったか、教えてくれます。

$ bundle install

Capybara が読み込まれるように設定ファイルを編集します。


spec/rails_helper.rb

# Add additional requires below this line. Rails is not loaded until this point!

require 'capybara/rspec'

Capybara で利用するウェブドライバーを指定します。


spec/support/capybara.rb

Capybara.javascript_driver = :selenium_chrome



基本的なコマンド

RSpecの基本的なコマンドは次のとおりです。


全テストの実行

$ bin/rspec


特定ファイルのテスト

$ bin/rspec spec/unit 


処理速度の遅いテストの検出

$ bin/rspec —-profile 2


キーワードが含まれるテストのみ実行

$ bin/rspec -e milk -fd

-e: example

-fd: full_description

* case-sensitive


失敗したテストだけ再実行

$ bin/rspec —-only-failure


便利なタグ

RSpec のテストコードで便利なタグを整理します。


aggregate_failures

デフォルトでは、テスト内でエラーが1つ発生すると、後続のエラーはメッセージに表示されません。

:aggregate_failures タグをつけると、発生するエラーを全て同時に確認できます。

RSpec.describe Ledger, :aggregate_failures do

# your test code
end

このタグを使ってアサーションをネストさせることもできます。

describe 'GET /your_root' do

it 'responds successfully' do
get your_root_path
aggregate_failures do
expect(response).to be_success
expect(response).to have_http_status '200'
end
end
end


focus

次のコマンドでテストを実行時すると focus: true タグがついてるテストのみ実行されます。

describe 'SOME TEST', focus: true do

it 'does something' do
expect(1).to eq(1)
end
end

$ bin/rspec --tag focus

各項目の頭に f をつけることでも、focus: true を指定できます。例えば、fcontext fit fdescribe のような具合です。

fdescribe 'SOME TEST' do

it 'does something' do
expect(1).to eq(1)
end
end

また、設定ファイル次のようにいじれば、bin/rspec コマンドだけで focus: true のみ(なければ全テスト)が実行されるようになります。


spec_helper.rb

RSpec.configure  do  |config|

config.filter_run_when_matching( focus: true )
end