🙆♀️
Rails7.13 サクッとRSpecを導入して単体テストする
はじめに
サクッとテストフレームワークRSpecを導入してモデルの単体テストの書き方について記述します。
実行環境
- M2 mac mini
- Rails 7.1.3
- Ruby 3.2.3
- Mysql 8.0
- Docker 25.0.2
- vscodeエディタ
環境構築が済んでいない方はこちらを参考に環境構築を行なってください。
Schemafileがまだの方はこちらから設定してください。
RSpecの導入
テストに必要なGemをGemfileに記述します。
Gemfile
group :development, :test do
# テストフレームワーク
gem 'rspec-rails'
# テスト用オブジェクトの生成gem
gem 'factory_bot_rails'
# ダミーデータの作成gem
gem "faker"
~~~~~~~~ 省略 ~~~~~~~~
gem "debug", platforms: %i[ mri mingw x64_mingw ]
end
追加したGemをインストール
docker-compose exec web bundle install
RSpecのセットアップ
docker-compose exec web rails g rspec:install
作成されるファイル
create spec # specの設定ファイル
create spec/spec_helper.rb # Railsの設定ファイル
create spec/rails_helper.rb # RSpecの全体的な設定ファイル
.rspecに以下の設定を追記すると、出力がドキュメント形式や色付けされて見やすくなります。
--require spec_helper
# 以下2つを追加
--color
--format documentation
FactoryBot設定
config.include FactoryBot::Syntax::Methods
を追加します。
spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
省略
~~~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~~~
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
abort e.to_s.strip
end
RSpec.configure do |config|
fixtures
config.fixture_paths = [
Rails.root.join('spec/fixtures')
]
~~~~~~~~~~~~~~ 追加 ~~~~~~~~~~~~~~~~
# FactoryBot設定
config.include FactoryBot::Syntax::Methods
~~~~~~~~~~~~~~ 追加 ~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~~~
end
自動生成ファイルの設定
config/application.rb
module App
class Application < Rails::Application
config.load_defaults 7.1
config.autoload_lib(ignore: %w(assets tasks))
~~~~~~~~ 省略 ~~~~~~~~
# ここから
config.generators do |g|
g.test_framework :rspec, # テストフレームワークとしてRSpecを指定
request_specs: false, # リクエストスペックを作成しない
fixtures: false, # テストデータを作るfixtureを作成しない
view_specs: false, # ビュー用のスペックを作成しない
helper_specs: false, # ヘルパー用のスペックを作成しない
routing_specs: false # ルーティングのスペックを作成しない
end
# ここまでを追加
end
end
controller、modelを生成すると、テスト用のファイルも生成できます。
生成されるテストファイルをRSpecに変更、Specファイルが生成されないように、上記の設定を行います。
以上でRSpecの設定は完了です。
SchemafileにTaskテーブルを記述
options = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
create_table "tasks", force: :cascade, options: options do |t|
t.string :title, null: false
t.string :content, null: false
t.boolean :is_completed, default: false, null: false
t.datetime :created_at, null: false
t.datetime :updated_at, null: false
end
Taskテーブルをマイグレーション
docker-compose exec web rake ridgepole:apply RAILS_ENV=test
RSpe Model作成
テスト用のtaskモデルの作成。「--skip-migration」コマンドでマーグレーションをスキップします。
docker-compose exec web rails g model Task --skip-migration
作成ファイル
invoke active_record
create app/models/task.rb
invoke rspec
create spec/models/task_spec.rb
invoke factory_bot
create spec/factories/task.rb
FactoryBot と Faker を使ってテストデータを生成する。
どんなものが用意されているかは公式リファレンスから確認してください。
モデルのバリデーション
app/models/task.rb
class Task < ApplicationRecord
validates :title, presence: true, length: { maximum: 10 } # titleが空でない&10文字以内であること
validates :content, presence: true, length: { maximum: 100 } # contentが空でない&100文字以内であること
end
テストデータの作成
spec/factories/tasks.rb
FactoryBot.define do
factory :task do
# 英数字のランダムな文字列を生成する(10文字)
title { Faker::Lorem.characters(number: 10) }
# 英数字のランダムな文字列を生成する(100文字)
content { Faker::Lorem.characters(number: 100) }
is_completed { false }
created_at { DateTime.now }
updated_at { DateTime.now }
end
end
モデルのテスト
spec/models/task_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
# given データの準備
let(:task) { build(:task) } # モデルのテストデータを準備
describe "title、contentのバリデーション" do # テストの対象が何かを記述する。
it "title、contentのバリデーションが通ること" do # 期待値を記述する
# when 変化
# then 結果を比較
expect(task).to be_valid
end
end
describe "titleのバリデーション" do # テストの対象が何かを記述する。
it "titleが空の場合はバリデーションする" do # 期待値を記述する
# when 変化
task.title = ''
# then 結果を比較
expect(task).to_not be_valid
end
it "titleが10文字を超える場合はバリデーションする" do
# when 変化
task.title = 'a' * 11
# then 結果を比較
expect(task).to_not be_valid
end
end
describe "contentのバリデーション" do # テストの対象が何かを記述する。
it "contentが空の場合はバリデーションする" do # 期待値を記述する
# when 変化
task.content = ''
# then 結果を比較
expect(task).to_not be_valid
end
it "contentが100文字を超える場合はバリデーションする" do
# when 変化
task.content = 'a' * 101
# then 結果を比較
expect(task).to_not be_valid
end
end
end
テストの実行
docker-compose exec web rspec spec/models/task_spec.rb
テスト結果
Task
title、contentのバリデーション
title、contentのバリデーションが通ること
titleのバリデーション
titleが空の場合はバリデーションする
titleが10文字を超える場合はバリデーションする
contentのバリデーション
contentが空の場合はバリデーションする
contentが100文字を超える場合はバリデーションする
Finished in 0.03728 seconds (files took 0.9696 seconds to load)
5 examples, 0 failures
まとめ
以上の設定によりテストを書く準備ができました。テストを書いてrailsライフを楽しみましょう。
Discussion