ここではGemファイルのRspec、rails-controller-testingを用いた
テストの大まかな流れを記載しています。
前提
【開発環境】
・Rails7
・Docker(DockerファイルにてGemのbundle installが行われるように設定済)
目次
・テストで使用するGem(RSpecとrails-controller-testing)をインストール
・コントローラー&モデルのテストで使用するファイルを作成
・テスト用のDB作成(必要な場合)
・テストの実行(モデルの場合)
・テストの実行(コントローラーの場合)
【テストで使用するGem(RSpecとrails-controller-testing)をインストール】
1 Gemfileを開きdevelopmentのテスト環境のブロックへrspec-railsを追記する。
rspec-railsのバージョンが古いと、scopeエラーが発生することがあるので、できるだけ最新をとってくるようにする。(これで結構はまっていました…)
group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "rspec-rails", "~> 4.0.2"
gem 'rails-controller-testing'
gem "debug", platforms: %i[ mri mingw x64_mingw ]
end
2 ターミナルでbuildコマンドを実行し、Gemをインストールする
docker-compose build
3 rspecの設定ファイルを生成する
docker-compose run web bundle exec rails g rspec:install
specフォルダ配下に以下が生成されていれば良い
spec/spec_helper.rb
spec/rails_helper.rb
【コントローラー&モデルのテストで使用するファイルを作成】
1 まずははじめにrailsのコンテナを起動する
# railsコンテナ立ち上げ
docker-compose up
# 起動しているかどうかの確認
docker-compose ps
起動しているかどうかの確認時に、「State」がupになっていれば良い
2 ユーザーモデルのテストを記載するファイルを作成する
docker-compose exec web bundle exec rails g rspec:model User
specフォルダ配下に以下が生成されていれば良い
spec/models/user_spec.rb
user_spec.rbのデフォルトの内容は以下
RSpec.discribe User, type: :model do
# ペンディングはデフォルトで記載されている(削除してよい)
pending "add some examples to (or delete) #{__FILE__}"
end
4 ユーザーコントローラーのテストを記載するファイルを作成する
docker-compose exec web bundle exec rails g rspec:controller Users
specフォルダ配下に以下が生成されていれば良い
spec/controllers/users_controller_spec.rb
users_controller_spec.rbのデフォルトの内容は以下
RSpec.describe UsersController, type: :controller do
end
【テスト用のDB作成(必要な場合)】
1 テスト用のDBを作成する
DB作成コマンドを実行する
docker-compose exec web bundle exec rails db:create
Railsでテストを実行する場合は、デフォルトでtestという環境で動作し、
DBもテスト用のものが使用される
【テストの実行(モデルの場合)】
# モデルのテスト実行コマンド
docker-compose exec web bundle exec rspec ./spec/models/
# example:実行したテスト failures:失敗したテスト pending:保留しているテスト
1 example, 0 failures, 1 pending
【メソッドの定義(テスト駆動開発)】
テスト駆動開発
…一度間違ったメソッドを定義して、テスト実行する
定義内容例
まずはモデルで「年齢」を定義する
class User < ApplicationRecord
def age
0
end
end
次にスペックファイルを記載する
reqire 'rails_helper'
RSpec.discribe User, type: :model do
# 何をテストするのかのテストの対象を記載(一般的には#メソッド名)
describe '#age' do
# どういう条件下で行うテストであるかを書く
context '5年前の生年月日の場合' do
# 上記contextが表すユーザーを定義
let(:user){User.new(birthday: Time.zone.now - 5.years) }
# 最終的にどういう状況であるのが正しいのかをテストする
it '年齢が5歳であること' do
# expectの中にはテスト対象とするメソッドの呼び出しなどを記載する
# 'eq'等の記載はマッチャーと呼ぶ(検索するときはexpect マッチャーと記載する)
expect(user.age).to eq 5
end
end
end
end
# ペンディングは削除する
# pending "add some examples to (or delete) #{__FILE__}"
end
この状態でテスト実行する
# モデルのテスト実行コマンド
docker-compose exec web bundle exec rspec ./spec/models/
app/models/user.rbで定義された値が0であり、
5ではないため以下のような結果が返ってくる
# example:実行したテスト failures:失敗したテスト pending:保留しているテスト
1 example, 1 failure
【メソッドの定義(正しく動作する場合)①】
まず生年月日から年齢を取得できるようにモデル側で定義する
class User < ApplicationRecord
def age
# 現在の日本時間
now = Time.zone.now
# 現在の日付と誕生日の日付をint型に直し、現在の日付 - 誕生日の日付を表す
# 結果を10000で割ることで年数を取得している
#(日付を引き算した年数の部分のみを取得して月以下の部分を切り捨てるために10000としている)→5桁目から上の部分を取得している
(now.strftime('%Y%m%d')).to_i - birthday.strftime('%Y%m%d').to_i) / 10000
end
end
テストの実行
# モデルのテスト実行コマンド
docker-compose exec web bundle exec rspec ./spec/models/
# example:実行したテスト failures:失敗したテスト pending:保留しているテスト
1 example, 0 failure
【メソッドの定義(正しく動作する場合)②】
境界値で確認するためにモックを準備する
モック
…テスト用にダミーのオブジェクトを用意したり、
特定のメソッドを選んだ場合に決まった値を返すように設定することができる。
# berforeブロック内でtimezoneなどの挙動を設定することができる
before do
allow(Time.zone).to receive(:now).and_return(Time.zone.parse('2024/04/01'))
end
context '5年前の生年月日の場合' do
# 上記contextが表すユーザーを定義
let(:user){User.new(birthday: Time.zone.now - 5.years) }
# 最終的にどういう状況であるのが正しいのかをテストする
it '年齢が5歳であること' do
# expectの中にはテスト対象とするメソッドの呼び出しなどを記載する
# 'eq'等の記載はマッチャーと呼ぶ(検索するときはexpect マッチャーと記載する)
expect(user.age).to eq 5
end
end
context '5年前に生まれてちょうど誕生日の場合' do
let(:user) {User.new(birthday: Time.zone.parse('2019/04/01')) }
it '年齢が5歳であること' do
expect(user.age).to eq 5
end
end
context '5年前に生まれて誕生日が来ていない場合' do
let(:user) {User.new(birthday: Time.zone.parse('2019/04/02')) }
it '年齢が4歳であること' do
expect(user.age).to eq 4
end
end
テストの実行
# モデルのテスト実行コマンド(ドキュメント形式でテスト結果を表示できるオプション(-f)付き)
docker-compose exec web bundle exec rspec -f d ./spec/models/
テスト実施結果(例)
User
#age
5年前の生年月日の場合
年齢が5歳であること
5年前に生まれてちょうど誕生日の場合
年齢が5歳であること
5年前に生まれて誕生日が来ていない場合
年齢が4歳であること
Finished in 0.11773 seconds (files took 5.81 seconds to load)
3 examples, 0 failures
このようにモデルの動作が正しいかどうかの確認を行うことができる。
【テストの実行(コントローラーの場合)】
ジェネレーターコマンドで作成しておいたコントローラーに以下を記載する。
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
describe 'GET #new' do
# beforeブロックではこのコントローラーアクションにGETのHTTPメソッドで擬似的にアクセスしている
# これによってGETのリクエスト結果がresponseという変数に格納される
before { get :new }
it 'レスポンスコードが200であること' do
expect(response).to have_http_status(:ok)
end
it 'newテンプレートをレンダリングすること' do
expect(response).to render_template :new
end
it '新しいuserオブジェクトがビューに渡されること' do
expect(assigns(:user)).to be_a_new(User)
end
end
end
テストの実行
# コントローラーのテスト実行コマンド(ドキュメント形式でテスト結果を表示できるオプション(-f)付き)
docker-compose exec web bundle exec rspec -f d ./spec/controllers/
テスト実施結果(例)
UsersController
GET #new
レスポンスコードが200であること
newテンプレートをレンダリングすること
新しいuserオブジェクトがビューに渡されること
Finished in 3.02 seconds (files took 5.69 seconds to load)
3 examples, 0 failures
このようにコントローラーが正しく動作しているかどうかを確認することができる。