Minitestで テストを書く
初めに
現場で使える Ruby on Rails 5速習実践ガイド では、開発現場で広く使われていることから、RSpecによってテストが書かれています。
しかしながら、初めて学ぶ方にとっては、RSpecは些か難しく感じるのではないでしょうか。
ここでは、Ruby on Rails の標準テストフレームワークであり、簡潔にテストを書ける Minitest を試してみます。
準備
Gemfile に minitest を追加。
minitest-reporters で、テスト結果を見やすくします。
# Gemfile
group :test do
gem 'capybara' # 仮想的に利用者のブラウザ操作を行う
gem 'selenium-webdriver'
gem 'webdrivers'
gem 'minitest' # Rails標準のテスト用フレームワーク
gem 'minitest-reporters' # テスト結果を見やすく表示
end
minitest-reporters で、テスト結果を見やすくするとともに、
利用者のログイン、ログアウトのテストを行えるよう、login_helperを追加します。
# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require_relative 'login_helper'
require 'rails/test_help'
require 'minitest/reporters'
Minitest::Reporters.use!
class ActiveSupport::TestCase
# parallelize(workers: :number_of_processors)
parallelize(workers: 1) # エラーが出るようならこちら
fixtures :all
end
# test/login_helper.rb
module LoginHelper
def login_as(user)
visit login_url
fill_in 'メールアドレス', with: user.email
fill_in 'パスワード', with: 'password'
click_on 'ログインする'
@current_user = user
end
def current_user
@current_user
end
end
fixture(フィクスチャ) を用意します。
フィクスチャとは、英語で造り付けの什器の意味です。
Railsは、このフィクスチャをテスト用のデータベースに自動的に読み込みます。
サンプルデータを作成するためには、Factory-bot等、より高機能なGemもありますが、ここでは、設定不要で簡潔に分かり易く導入できるfixtureを使います。
# test/fixtures/users.yml
# 一般の利用者 taro
taro:
name: taro
email: taro@example.com
password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
admin: true
# 管理者 admin
admin:
name: admin
email: admin@example.com
password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
admin: true
# 十人の利用者を作ることもできます。
<% 1.upto(10) do |i| %>
user_<%= i %>:
name: user_<%= i %>
email: user_<%= i %>@example.com
password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
admin: false
<% end %>
fixtureは、user: taro と書くことで、関連付けを設定することもできます。
# test/fixtures/tasks.yml
taro_task:
name: 太郎のタスク
description: タスクの説明いろいろ
user: taro
システムテスト
システムテストは、ウェブアプリを実際に利用者がブラウザで操作した場合のテストを行います。
少し実行に時間がかかることもありますが、利用者の操作を模倣でき、また失敗した際にはスクリーンショットも自動で取られるので、便利です。
テストの作成
Rails には、システムテストを容易に作成できるようジェネレータが実装されています。
% rails g system_test welcomes
このコマンドを実行することで、システムテストの雛型が作成されますので、少し手を加えます。
# test/system/welcomes_test.rb
require "application_system_test_case"
class WelcomesTest < ApplicationSystemTestCase
test "トップページに Taskleaf と表示されている" do
visit root_url
assert_selector "h1", text: "Taskleaf"
end
end
テストの実行
以下のコマンドで、全てのシステムテストが実行できます。
% rails test:system
一部のテストを実行するには、次のコマンドを使います。
% rails test test/system/welcomes_test.rb
システムテストが失敗したようです。
失敗すると、自動的にスクリーンショットが取られます。
taskleaf/tmp/screenshots/
failures_test_トップページに_Taskleaf_と表示されている.png ```
と表示されていますので、Finderで確認できます。
スクリーンショットをもとに、エラーを修正してもう一度実行します。
![スクリーンショット 0002-12-13 23.03.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96314/df26ef14-494f-2168-739c-8d03b333149b.jpeg)
無事にシステムテストが通りました。
### 利用者のテスト
``` ruby
# test/system/users_test.rb
require "application_system_test_case"
class UsersTest < ApplicationSystemTestCase
setup do
@user = users(:taro)
end
test "パスワードが正しいと、ログインできる" do
visit login_url
fill_in 'メールアドレス', with: @user.email
fill_in 'パスワード', with: 'password'
click_on 'ログインする'
assert_selector ".ui.success.message", text: "ログインしました"
end
test "パスワードが違うと、ログインできない" do
visit login_url
fill_in 'メールアドレス', with: @user.email
fill_in 'パスワード', with: 'wrong password'
click_on 'ログインする'
assert_selector ".ui.error.message", text: "メールアドレス または パスワードが異なります"
end
end
タスクのテスト
setup ブロックで事前準備すると、その後のテストでずっと使えるので便利です。
# test/system/tasks_test.rb
require "application_system_test_case"
class TasksTest < ApplicationSystemTestCase
setup do
@taro = users(:taro)
@jiro = users(:jiro)
@taro_task1 = tasks(:taro_task1)
@taro_task2 = tasks(:taro_task2)
@taro_task3 = tasks(:taro_task3)
@jiro_task1 = tasks(:jiro_task1)
end
test "太郎でログインすると、太郎が作成したタスクが一覧表示される" do
login_as(@taro)
visit tasks_path
assert_text @taro_task1.name
assert_text @taro_task2.name
assert_text @taro_task3.name
end
test "太郎でログインすると、太郎が作成したタスクが詳細表示される" do
login_as(@taro)
visit task_path(@taro_task1)
assert_text @taro_task1.name
assert_text @taro_task1.description
end
test "次郎でログインすると、太郎が作成したタスクが表示されない" do
login_as(@jiro)
visit tasks_path
assert_no_text @taro_task1.name
end
test "新規作成画面で名前を入力すると、タスクが登録できる" do
login_as(@taro)
visit new_task_path
fill_in '名前', with: '新しい太郎のタスク'
click_on '登録する'
assert_selector '.ui.success.message', text: '新しい太郎のタスク'
within 'table' do
assert_text '新しい太郎のタスク'
end
end
test "新規作成画面で名前がないと、エラーが表示される" do
login_as(@taro)
visit new_task_path
fill_in '名前', with: ' '
click_on '登録する'
within '#error_explanation' do
assert_text '名前を入力してください'
end
end
test "自分のタスクを編輯できる" do
login_as(@taro)
visit tasks_path
click_on '編輯', match: :first
fill_in '名前', with: '編輯した太郎のタスク'
click_on '更新する'
assert_selector '.ui.success.message', text: '編輯した太郎のタスク'
within 'table' do
assert_text '編輯した太郎のタスク'
end
end
test "自分のタスクは削除できる" do
login_as(@taro)
assert_equal 3, current_user.tasks.count
visit tasks_path
click_on '削除', match: :first
accept_confirm
assert_selector '.ui.success.message', text: '削除しました'
assert_equal 2, current_user.tasks.count
end
end
メールのテスト
メールの送信テストをすることもできます。
# test/mailers/task_mailer_test.rb
require 'test_helper'
class TaskMailerTest < ActionMailer::TestCase
# 事前準備
setup do
@user = users(:taro)
@task = @user.tasks.create(name: '本日のタスク',
description: 'Ruby on Railsの学習をする')
@mail = TaskMailer.creation_email(@task)
end
test "タスク作成完了メールが送信されること" do
# メール送信されるかをテスト
assert_emails 1 do
@mail.deliver_now
end
# 期待通りのメールを送信したかをテスト
assert_equal "タスク作成完了メール", @mail.subject
assert_equal [@user.email], @mail.to
assert_equal ["taskleaf@example.com"], @mail.from
assert_match "本日のタスク", @mail.html_part.body.to_s
assert_match "Ruby on Railsの学習をする", @mail.html_part.body.to_s
assert_match "本日のタスク", @mail.text_part.body.to_s
assert_match "Ruby on Railsの学習をする", @mail.text_part.body.to_s
end
end
以下のコマンドで、メーラーのテストを実行します。
% rails test test/mailers
最後に
簡潔に書けるminitestのご紹介、いかがでしたでしょうか?
皆様のお役に立てば幸いです。
Discussion