読者です 読者をやめる 読者になる 読者になる

kikeda1104's blog

備忘録・技術に関することを書いています。(webエンジニア)

フィーチャーテスト(Rails + Rspec + Capybara)

追記: コメントをいただきまして、一部内容を更新しています。

今朝、rspec 3.5リリースの記事*1rspecの公式HPから確認した所

Rails 5 では、 assigns と assert_template が soft deprecated になりました。

という内容が書いてあり、今までcontroller specに書いていたテストの一部をrequest specに移すことになりそうです。

controller specでテストする内容は、responseとレコードの新規/更新/削除になるのかと思います。

assignsが使えず*2インスタンス変数にアクセスできなくなっているため、 controller specでテストするのではなく、別のspecでテストを書くことになりそうです。

本題に戻ります。 自作アプリにフィーチャーテストを追加しまして、まとめていきます。 model, controllerと、poltergeistの準備についても省いています。

Gemfile

# Gemfile
...

group :development, :test do
  ...
  gem 'factory_girl_rails'
end
...

group :development do
  gem 'capybara'
  gem 'poltergeist'
  gem 'launchy'
  gem 'database_cleaner'
  # 一部削除しました。
  gem 'simplecov', require: false
end

simplecovは、テストカバレッジを見るgemになるので、外しても良いです。 simplecovを利用する上で必要な設定は引き続きで、記事にのせています。

利用する場合、htmlが作成されますが、rails sからアクセスできる場所にファイルが保存されないため、 rubyからwebrickを起動するスクリプトを書くと使い易くなります。

spec/rails_helper.rb

rails_helperに追加していきます。

# rails_helper.rb

...
require 'simplecov'

SimpleCov.start('rails') do
  add_filter '/vendor/'
end

require 'capybara/rspec'
require 'cabtpara/poltergeist'
Capybara.javascript_driver = :poltergeist

Rspec.configure do |config|
...

  # sample
  # RSpec.configure do |c|
  # c.before(:each)  { } # :each 全てのテストスイート中のそれぞれのexampleの前に実行される
  #  c.before(:all)   { } # :all それぞれのトップレベルのグループの最初のexampleの前に実行される
  #  c.before(:suite) { } # :suite 全てのspecファイルがロードされたあと、最初のspecが実行される前に一度だけ実行される
  #end

  # exampleは、eachのalias
  # contextは、allのalias
  
  # https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
        (or set it to false) to prevent uncommitted transactions being used in
        JavaScript-dependent specs.

        During testing, the app-under-test that the browser driver connects to
        uses a different database connection to the database connection used by
        the spec. The app's database connection would not be able to access
        uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    load Rails.root.join('db', 'seeds.rb')
    DatabaseCleaner.clean_with, :truncation, { except: %w(master_tables) }
  end 

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :feature) do
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      DatabaseCleaner.strategy = :truncation
    end
  end

  config.before(:each) do 
    DatabaseCleaner.start
  end

  config.append_after(:each) do
    load Rails.root.join('db', 'seeds.rb')
    DatabaseCleaner.clean
  end
...
  config.include LoginMacro
end

factories

最低限のfactoryを準備します。

# spec/factories/users.rb

FactoryGirl.define do
  factory :user do
    email: 'user@example.com'
    password 'secret'
    password_confirmation 'secret'
  end
end

spec/support/login_macro.rb

# spec/support/login_macro.rb
module LoginMacro
  ...
  
  def sign_in(user)
    visit admin_sessions_new_path
    fill_in 'user_email', with: user.email
    fill_in 'user_password', with: 'secret'
    click_on 'Submit'
  end
end

spec/support/shared_db_connection.rb

コメントをいただきまして、最新のdatabase_cleanerを利用する場合、不要になっています。

feature

featureテストを追加します。

# spec/features/user_login_spec.rb
require 'rails_helper'

Rspec.feature 'Authenticate', type: :feature do
  scenario 'login user', js: true do
    user = create(:user)
    sign_in(user)
    expect(page).to have_content user.company.name
  end
end

追記: scenarioに追加されているオプションjs: trueにより、javascriptを動作させることができます。

テスト実行

$ bundle exec rspec spec/features/admin_login_spec.rb
.

Finished in 7.05 seconds (files took 2.76 seconds to load)
1 example, 0 failures

Coverage report generated for RSpec to /home/user_name/application_name/coverage. 130 / 448 LOC (29.02%) covered.

Coverage...は、simplecovが出力するログです。

以上になります。

参考

Feature spec - Feature specs - RSpec Rails - RSpec - Relish

使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 - Qiita

RSpec 3の重要な変更 - 有頂天Ruby

CentOS6にyumでphantomjs 2.1.1をインストール - Qiita

[Ruby] よく使うRspecのレシピ集(Rspec3.3) | Developers.IO

*1:http://rspec.info/ja/blog/2016/07/rspec-3-5-has-been-released/

*2:gemを入れることで利用することはできるが新規アプリでは非推奨