101
89

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RSpecコトハジメ ~初期設定マニュアル~

Last updated at Posted at 2019-01-21

はじめに

RSpecをRailsアプリで使用する際、「どのgem入れなきゃいけないんだっけ」「あの設定ってどうやって書くんだっけ?」といったことが多かったので、自分なりの初期設定をまとめてみました。

support配下のファイル有効化

RSpecのテストで共通化したい処理は、モジュールにしてspec/support配下に置くのがお作法。

今回は、

  • spec内で共有したい処理はspec/support/helperディレクトリ配下にモジュールを作成
  • initialize時に読み込む設定ファイルはspec/support/configディレクトリ配下に作成

という方針をとり、それぞれspec/rails_helper.rbから読み込むよう設定。

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

指定したテストタイプで、helper配下に作成したモジュールを読み込むことで、spec内でモジュールに定義された処理が使用できる。

spec/rails_helper.rb
RSpec.configure do |config|
  config.include ◯◯(モジュール名), type: :☓☓(使用するテストのタイプ)
end

各spec内で読み込むmoduleを都度指定しても良い。

specファイル
RSpec.feature 'Home', type: :system do
  include ◯◯(モジュール名)
end

gemの追加

諸々必要となるgemを追加し、設定を施していきます。

rspec-rails

RSpecの機能をRailsで使用するためのgem

Gemfile
gem 'rspec-rails'

gem追加後、下記コマンドを実行

$ rails g rspec:install

コマンド実行後、下記ファイルが作成される

create .rspec
create spec/spec_helper.rb   #RSpecの全体的な設定を書く
create spec/rails_helper.rb  #Rails特有の設定を書く

factory_bot

テストデータ生成用のgem

Gemfile
gem 'factory_bot_rails'

下記設定により、FactoryBotのデータ呼び出しを簡略化できる。
(テストデータの呼び出しを、FactoryBot.create(:◯◯)create(:◯◯)に簡略化出来る)

spec/support/config/factory_bot.rb
require 'factory_bot'

RSpec.configure do |config|
 config.include FactoryBot::Syntax::Methods
end

また、springを使用してrspecを動かしていると、factoryで作成したデータが正しく読み込まれないことがある。
そんな時は、下記を設定ファイルに追記して、毎回全てのexample実行前にfactory_botを再読込させる。

spec/support/config/factory_bot.rb
require 'factory_bot'

RSpec.configure do |config|
 config.before :all do
  FactoryBot.reload
 end
end

spring-commands-rspec

springでrspecを使用することで高速化を図る。

Gemfile
gem 'spring-commands-rspec'

gem追加後、下記コマンド実行で、bin/rspecが作られる

$ spring binstub rspec

bin/rspec作成後は、下記コマンド実行でrspecをspringで使用できる。

$ bin/rspec

capybara

インテグレーション・テストの補助ツール

Gemfile
gem 'capybara'

capybaraの読み込み

spec/support/config/capybara.rb
require 'capybara/rspec'

launchy

feaatureテスト中にsave_and_open_pageを記載することで、キャプチャのHTMLを自動で開くことが出来るgem

Gemfilr
gem 'launchy'

chromedriver-helper

seleniumとchromeのインターフェース

Gemfile
gem 'chromedriver-helper'

jsを使用するsystem specの場合はchromeのヘッドレスドライバを使用するよう設定する。
(※jsを使用しないテストの場合は、高速なRack::Testドライバを使用)

spec/support/config/capybara.rb
require 'capybara/rspec'

RSpec.configure do |config|
 config.before(:each, type: :system) do
  driven_by :rack_test
 end

 config.before(:each, type: :system, js: true) do
  driven_by :selenium_chrome_headless
 end
end

shoulda-matchers

リッチなマッチャが使えるようになる。
shoulda-matchers

Gemfile
gem 'shoulda-matchers'

# rails5以降の場合、 
gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5'

requireした上で、初期設定を施す。

spec/support/config/shoulda_matcher.rb
require 'shoulda/matchers'

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

VCR

API呼び出し時に、一回目の呼び出しを記録して、次回以降は記録されたレスポンスを返してくれる
(ちなみに、VCRは、Video Cassette Recordeの略)

Gemfile
gem 'vcr'
gem 'webmock' #vcrの処理時に水面下で利用されるHTTPスタブ化ライブラリ

外部HTTPリクエスト送信時にVCRを使用する設定を追加

spec/support/config/vcr.rb
require 'vcr'

VCR.configure do |config|
 config.cassette_library_dir = "#{ ::Rails.root }/spec/cassettes"
 config.hook_into :webmock
 config.ignore_localhost = true
 config.configure_rspec_metadata!
end

exampleのオプションにvcr: trueをつけることで、外部HTTPリクエストがVCR経由で行われるようになる。

it 'hoge', vcr: true do
 exampleの中身
end

simplecov

rspec実行時にcoverageというフォルダが自動で作成され、その中にテストのカバレッジを計測したHTMLファイルを自動で配置してくれるようになる。

Gemfile
gem 'simplecov'
spec/rspec_helper.rb
require 'simplecov'

SimpleCov.start 'rails'

あとはいつも通りテストを実行するだけ。

database_cleaner

テスト毎にDBをリセットすることで、テストの独立性を担保できる。

Gemfile
gem 'database_cleaner'

DatabaseCleanerの設定を追加

spec/support/config/database.rb
RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end
  config.before(:each) do
    DatabaseCleaner.start
  end
  config.after(:each) do
    DatabaseCleaner.clean
  end
end

これで、specを実行するたびにDB内のデータが削除される。

※Rails5.1以上では、デフォルトでDatabaseCleanerが組み込まれているため、gemをインストールする必要はありません。

初期設定に含めていないgem達

名前はよく聞くけども、各々の理由で初期設定に含めていないgemも列挙しておきます。
必要に応じて追加してください。

faker

ダミーデータの生成を楽にしてくれるgem。
特に必要性を感じてないので入れてないです。

funbar

specの進捗状況を可視化してくれるgem(全体でいくつexampleがあって、そのうち何個終了したか等が見やすくなる)
むしろ見づらくなってる気がするので入れてないです。(主観ですw)

.rspec

RSpecの設定ファイル
下記のように設定。

.rspec
--color
--require spec_helper
--format documentation

タグ

各exampleに、独自のタグを設定することが出来る。

focusタグがついたspecがあればそれだけ実行、なければ全spec実行する設定を追加。

spec/spec_helper.rb
RSpec.configure do |config|
  config.filter_run focus: true
  config.run_all_when_everything_filtered = true
end

exampleにfocusタグを付ける場合は、こんな感じ

サンプルexample
it 'hoge', :focus do
 exampleの中身
end

seedデータの挿入

テスト開始前にDBにデータを入れておきたい場合、ありますよね。
僕はいつもseed-fuを使用しているので、

db/fixtures/test/○○.rb
User.seed(:id,
  { id: 1,
    name: 'User',
    email: 'user@user.jp',
    password: 'password',
    password_confirmation: 'password',
  },
)

こんな感じでspec実行前に挿入したいseedデータを、db/fixtures/test配下に用意しておいて、

spec/spec_helper.rb
RSpec.configure do |config|
  config.before :suite do
    fixture_paths = "#{Rails.root}/db/fixtures/test"
    SeedFu.seed(fixture_paths)
   end
end

こんな感じで、テスト実行前にデータを挿入してます。

ちなみにこのSeedFu.seedの第二引数にはフィルターが渡せるので、特定のファイルのみ実行したい場合はフィルターを追加してあげてください。

ファイルアップロード

テスト時は/spec/test_uploads配下に画像をアップロードする設定を追加
(spec/test_uploads配下の指定は適当でOK)

Paperclipを使用する場合
config/environments/test.rb
Paperclip::Attachment.default_options[:path] = \
 "#{ Rails.root }/spec/test_uploads/:class/:style.:extention"
Carrierwaveを使用する場合
app/uploaders/◯◯_uploader.rb
def store_dir
 if Rails.env.test?
  "spec/test_uploads/#{model.class.to_s.underscore}
 else
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
 end
end

テストの実行が終わったらアップロードされたファイルを削除する処理を追加。

spec/rails_helper.rb
RSpec.configure do |config|
 config.after(:suite) do
  FileUtils.rm_rf(Dir["#{ Rails.root }/spec/test_uploads/"])
 end
end

gitignoreに、テスト時にアップロードされたファイルを無視する設定を追加

:.gitignore
/spec/test_uploads

各種specファイルの生成

ジェネレーター使用時は不要なテストファイルが作られないように設定
(全部自動で作成されてしまうとファイルが増えてごちゃごちゃするのであまり好きじゃない)

config/application.rb
config.generators do |g|
  g.test_framework :rspec,
    fixtures: true,
    view_specs: false,
    helper_specs: false,
    routing_specs: false,
    controller_specs: false,
    request_specs: false
  g.fixture_replacement :factory_bot, dir: "spec/factories"
end

必要になったらジェネレーター経由でテストファイルを作成

model_specの作成
$ rails g rspec:model ◯◯
factoryの作成
$ rails g factory_bot:model ◯◯
feature_specの作成
$ rails g rspec:feature ◯◯
request_specの作成
$ rails g rspec:request ◯◯

初期設定一覧

最後に、上記の設定をひとまとめにします。
ごちゃごちゃしてややこしい!  という方は、何も考えず下記をコピーすればとりあえずOKです。

config/application.rb
config.generators do |g|
  g.test_framework :rspec,
    fixtures: true,
    view_specs: false,
    helper_specs: false,
    routing_specs: false,
    controller_specs: false,
    request_specs: false
  g.fixture_replacement :factory_bot, dir: "spec/factories"
end
.rspec
--color
--require spec_helper
--format documentation
spec/rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?

require 'simplecov'
require 'capybara/rspec'
require 'factory_bot'
require 'shoulda-matchers'
require 'vcr'
require 'spec_helper'
require 'rspec/rails'


# テスト実行前に未実行のmigrationファイルを検知して実行する
begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  puts e.to_s.strip
  exit 1
end

# support/config配下のファイルを読み込み
Dir[Rails.root.join("spec/support/config/*.rb")].each { |f| require f }
Dir[Rails.root.join("spec/support/helper/*.rb")].each { |f| require f }

RSpec.configure do |config|

  # focusタグがあればそれだけ実行、なければ全spec実行
  config.filter_run focus: true
  config.run_all_when_everything_filtered = true

  # ロードするfixtureのパスを指定
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # ディレクトリ構成によってspec typeを自動判別する設定
  config.infer_spec_type_from_file_location!

  # spec実行後のbacktrace表示を簡素化
  config.filter_rails_from_backtrace!
end
spec/spec_helper.rb
require 'simplecov'

SimpleCov.start 'rails'

RSpec.configure do |config|
  # focusタグがあればそれだけ実行、なければ全spec実行
  config.filter_run focus: true
  config.run_all_when_everything_filtered = true

  # specをランダム実行
  config.order = :random
end
spec/support/config/factory_bot.rb
RSpec.configure do |config|
  # FactoryBotの呼び出し簡略化
  config.include FactoryBot::Syntax::Methods

  # springが原因でfactoryが正しく読み込まれないことを防ぐ
  config.before :all do
    FactoryBot.reload
  end
end
spec/support/config/capybara.rb
RSpec.configure do |config|
 config.before(:each, type: :system) do
  driven_by :rack_test
 end

 config.before(:each, type: :system, js: true) do
  driven_by :selenium_chrome_headless
 end
end
spec/spoort/config/database.rb
RSpec.configure do |config|
  # database_cleanerの設定
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end
  config.before(:each) do
    DatabaseCleaner.start
  end
  config.after(:each) do
    DatabaseCleaner.clean
  end
end
spec/support/config/file_upload.rb
RSpec.configure do |config|
  # テスト実行後にアップロードされたファイルを削除
  config.after(:suite) do
    FileUtils.rm_rf(Dir["#{ Rails.root }/spec/test_uploads/"])
  end
end
spec/support/shoulda_matcher.rb
# shoulda-mathcerの設定
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
spec/support/config/vcr.rb
VCR.configure do |config|
  config.cassette_library_dir = "#{ ::Rails.root }/spec/cassettes"
  config.hook_into :webmock
  config.ignore_localhost = true
  config.configure_rspec_metadata!
end

最後に

「こんな設定あるよー」とか「これ便利だよー」みたいなのあれば、教えてほしいです!

101
89
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
101
89

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?