LoginSignup
95
95

More than 3 years have passed since last update.

基礎からやり直す Rails RSpec

Last updated at Posted at 2019-05-14

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) と書くだけでデータ生成できるようになりました。

ダミーデータ生成用の設定

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

Gemfile
group :development, :test do
  gem 'faker', git: 'https://github.com/stympy/faker.git', branch: 'master'
  gem 'forgery_ja'
end
$ bundle install

これらを使えば、FactoryBot で任意のダミーデータをセットできます。(Faker は英数字用、ForgeryJa は日本語用です。)

spec/factories/some_model.rb
require 'faker'
require 'forgery_ja'

FactoryBot.define do
  factory :some_model do
    name { ForgeryJa(:name).full_name }
    name_kana { ForgeryJa(:name).full_name(to: ForgeryJa::KANA) }
    zip_code { Faker::Number.number(digits: 7).to_s }
    code { Faker::Lorem.characters(number: 20) }
    sex { Faker::Number.between(from: 0, to: 2) }
    birthday { Faker::Date.birthday(min_age: 18, max_age: 65) 
    phone { Faker::Number.number(digits: Faker::Number.between(from: 10, to: 11)) }
    email { ForgeryJa('email').address }
  end
end

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

ヘッドレスブラウザとして動かしたい場合は、次のように書きます。

spec/support/capybara.rb
require 'capybara/rspec'
require 'selenium-webdriver'

Capybara.register_driver :headless_chrome do |app|
  opts = {
    browser: :chrome,
    desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
      chrome_options: { args: %w[headless disable-gpu window-size=1680,1050 start-maximized] }
    )
  }
  Capybara::Selenium::Driver.new(app, opts)
end

Capybara.javascript_driver = :headless_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
95
95
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
95
95