こんにちは。アルバイトのハオと申します。初めての記事で、よろしくお願いいたします。

Ruby on Rails (略称Rails) は、Webアプリのフレームワークであります。

今はRailsを使って会社の内部向け運用管理画面を構築しています。最近この管理画面に対してテストをしまして、テスト作成の経験をシェアしたいと思います。

今回の記事は、こちらを参考にして作成した、タスク管理アプリ(todoアプリ)に対するテストをテーマにします。

少しこのアプリを紹介します。このアプリはユーザー新規登録、ログイン、そしてユーザーのタスクの新規追加、更新、削除ができます。これからアプリの画面を見せます。

まずはユーザー新規登録、ユーザーログインの画面です。


タスク一覧画面です。ログインしているユーザーのタスクを全部表します。上にタスク新規追加のボタンがあり、タスク行の右に編集と削除ボタンもあります。

タスク新規追加の画面です。タイトル、ノート、タスク完成の時間を入力できます。

タスク編集の画面です。タイトル、ノート、タスク完成の時間を更新できます。

では、テストの作成に入りましょう。

chromedriverをダウンロード

テストのため、chromedriverでgoogle chromeを起動する必要があります。

持っているgoogle chromeのバージョンと合致したchromedriverをダウンロード

WSLの方はwindows環境にダウンロードし、chromedriver.exeをCドライブに移します。

例えば、僕はC:\Program Files\chromedriver_win32\に移しました。

あとでchromedriverへのパスを指定します。

必要なgemをインストール

Gemfile のtest グループを以下の通りに編集

group :test do
gem 'capybara', '>= 2.18'
gem 'rspec-rails', '>= 3.7' #追加
gem 'selenium-webdriver'
gem 'capybara-email' #追加
gem 'email_spec' #追加
# 下の行を削除してください
# gem 'chromedriver-helper'
end

今回はheadless chromeを使うため、chromedriver-helperはいりません。ちなみにchromedriver-helperはサポートがもう終了したようです(https://github.com/flavorjones/chromedriver-helper)

追加したgemをインストール

$ bundle install

テスト環境の設定

$ bundle exec rails g rspec:install

を実行することで、spec/rails_helper.rbspec/spec_helper.rbが新規作成されます。

まずspec/spec_helper.rbを編集しましょう。ファイルに、ダウンロードしたchromedriverのパスを指定:

require 'selenium-webdriver'
Selenium::WebDriver::Chrome.driver_path = "/mnt/c/Program Files/chromedriver_win32/chromedriver.exe"

同じファイルの下にあるRSpec.configureの設定で、config.formatter = :documentationを追加することをおすすめです。これによってテストするときに、scenarioごとにタイトルが出力されます。

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
  config.shared_context_metadata_behavior = :apply_to_host_groups
  # Print the name of each scenario
  config.formatter = :documentation #追加
end

次はspec/rails_helper.rbです。capybara/railscapybara/email/rspec'をインポート:

require 'capybara/rails'
require 'capybara/email/rspec'

続いてheadless chromeに関する設定を追加:

Capybara.default_driver = :selenium_chrome_headless

Capybara.register_driver :selenium_chrome_headless do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('headless')
  options.add_argument('--disable-gpu')
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

続いて下のActiveRecordに関する設定を削除してください:

begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  puts e.to_s.strip
  exit 1
end

これを無効にしないと、テスト時に自動的にDBにmigrationがかかってしまいます。既にDBにテーブルが存在していてmigrationを使わない方にとっては、DBの内容を消去されてしまう恐れがあります。

続いて同じファイルの下にあるRSpec.configureの方を編集します。

RSpec.configure do |config|
  config.include Capybara::DSL #追加
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  # 次の行を削除またはコメントアウト又はfalseにしてください
  # config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!
end

メールに関する設定

今回テスト対象としたToDoアプリの場合、テストアカウントを新規登録する際に確認メールが送信されますので、それについても設定しなければなりません。

config/environments/test.rbを編集しましょう。

まず以下の行があるかどうか確認:

config.action_mailer.delivery_method = :test

この設定で、実在するメールアドレスへの送信は行われなくなります。

そしてホストを追加:

config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost', :port => '3000' }

テストファイルの作成

以下のコマンドを実行してテストファイルを作成してください。

$ mkdir spec/features/
$ vim spec/features/todo_spec.rb

このサイトを参考してテストを書きましょう。

spec/features/todo_spec.rbの中身:

require "rails_helper"

feature "Todoアプリ、アカウントとタスクのテスト" do
  given(:email) { 'example@rooter.co.jp' }
  given(:password) { '000000' }

  scenario "アカウントを新規登録テスト" do
    visit "/users/sign_up" #新規登録画面へ
    fill_in "user_email", with: email
    fill_in "user_password", with: password
    fill_in "user_password_confirmation", with: password

    click_button "Sign up"
    sleep 3

    open_email(email) #確認メールを開く
    current_email.click_link 'Confirm my account' #アカウント確認リンクを押す

    new_user = User.find_for_authentication(email: email)
    expect(new_user).to be_confirmed #アカウントが確認されたかどうか
  end

  feature "登録したアカウントでテスト" do
    background do
      visit root_path #ホームページにアクセスし、まだログインしていないのでログイン画面に自動遷移
      fill_in "user_email", with: email
      fill_in "user_password", with: password
      click_button "Sign in"
    end

    scenario "タスク新規" do
      click_on "New task" #タスク新規の画面を開く
      fill_in "task_title", with: "test new task"
      click_on "Save"

      expect(page).to have_selector('td string', text: "test new task")
    end

    scenario "タスク編集" do
      find("i.icon-edit").click #タスク編集の画面を開く
      fill_in "task_title", with: "test edit task"
      click_on "Save"

      expect(page).to have_selector('td string', text: "test edit task").and have_no_selector('td string', text: "test new task")
    end

    scenario "タスク削除" do
      page.accept_alert do
        # 警告が出てくるアクションをこの中に包む
        find("i.icon-remove").click
      end

      expect(page).to have_no_selector('td string', text: "test edit task").and have_no_selector('td string', text: "test new task")
    end

    scenario "アカウントを削除テスト" do
      visit "/users/edit" #アカウント編集画面へ

      page.accept_alert 'Are you sure?' do
        # 'Are you sure?'警告が出てくるアクションをこの中に包む
        click_link "Cancel my account"
      end
      sleep 3

      user = User.find_by(email: email)
      expect(user).to eq nil
    end

  end
end

テストを実行しましょう!

$ bundle exec rspec spec/features/todo_spec.rb

緑文字ばかりで、赤い文字がなければ成功です。

参考資料