RSpecのペアプロで学んだモデルテストの書き方(備忘録)
はじめに
初めてペアプロに参加させていただき、そこでRSpecでモデルテストを書く流れを学びました。
この記事は自分用の備忘録として、まとめておきます。
(ペアプロ自体の体験記事は、また別で)
describe / context / it の使い分けについて
RSpecではこの3つをよく使います。最初は全部同じに見えたけど、役割を意識すると整理できる。
RSpec.describe User, type: :model do
describe "バリデーション" do
context "有効な場合" do
it "バリデーションを通る" do
# テストコード
end
end
end
end
- describe: テスト対象や観点を書く(例: "バリデーション", "インスタンスメソッド")
- context: 条件を書く(例: "有効な場合", "名前が空の場合")
- it: 期待値を書く(例: "バリデーションを通る")
書き方の流れは「何をテストする → どんな条件 → どうなるべきか」となる
正常系と異常系を分ける
- 正常系
まずは「正しく動く場合」
context "有効な場合" do
let(:user) { build(:user) }
it "バリデーションを通る" do
expect(user.valid?).to be true
end
end
ポイントとして
-
letでテストデータを簡潔に定義できる -
valid?メソッドでバリデーションが通るかをチェックする
- 異常系
「エラーになる場合」
context "名前が空の場合" do
let(:user) { build(:user, name: '') }
it "無効である" do
expect(user.valid?).to be false
expect(user.errors[:name]).to include("を入力してください")
end
end
異常系では「バリデーションが失敗する」+「正しいエラーメッセージが出る」を両方確認する。
build と create の違い
何度も出てきた重要ポイント
# build: User.new と同じ (DBに保存しない)
let(:user) { build(:user, name: "") }
# create: User.create! と同じ (DBに保存する)
create(:user, email: "test@example.com")
- 基本は
buildを使う(DBに書き込まないので速い) - 他のレコードとの関係をテストしたいときだけ
createを使う - 「DBに保存が必要かどうか」で判断する
重複チェックのテスト
メールアドレス重複をテストする時はcreateが必要
context "メールアドレスが重複している場合" do
it "無効である" do
create(:user, email: "test@example.com") # 先にDBに保存
user = build(:user, email: "test@example.com")
expect(user.valid?).to be false
expect(user.errors[:email]).to include("はすでに存在します")
end
end
- 「すでに存在する状態」を作るために
createを使う
エラー検証の2つの方法
ペアプロで学んだエラーチェックの書き方
includeを使う
expect(user.errors[:email]).to include("を入力してください")
メッセージの一部が含まれているかを確認するため
be_of_kindを使う
expect(user.errors).to be_of_kind(:password, :blank)
- エラーの種類でチェックできる
- メッセージが変わってもテストが壊れにくい
メールアドレス形式のバリデーション
-
formatのテストも書けるらしい
context "メールアドレスの形式が不正な場合" do
it "無効である" do
user = build(:user, email: "090-1111-2222")
expect(user.valid?).to be false
expect(user.errors).to be_of_kind(:email, :invalid_format)
end
end
- 明らかにメールアドレスでない文字列でテストするのが良き
contextのネストについて
- ネストはできるだけ浅くする
- やっても2段階までがいいみたい
# Good
describe "バリデーション" do
context "名前が空の場合" do
it "無効である" do
end
end
context "メールアドレスが空の場合" do
it "無効である" do
end
end
end
テストを書くときの流れ
- 何をテストするか決める(describe)
- どんな条件か考える(context)
- どうなるべきか書く(it)
- テストデータを準備する(let, build, create)
- 検証する(expect)
- この流れで考えるとスムーズに書ける
まとめ
学んだこととして
- describe / context / it の役割を理解
-
buildとcreateの違い - 正常系から書いて異常系を追加していく流れ
- エラーチェック方法が今回学んだこと以外にもたくさんある
-
contextのネストは浅くする
RSpecは半年ぶりに触りました。
「とりあえず、このパターンで書けばいい」という形が少し見えてきた気がします。
引き続き、書いていきたいと思います。
初学者のため、記事が間違えていたらすいません。