RSpecでBDDテスト術
Ruby応用とRSpecの基礎
Rails アプリケーションを開発する際、テストは欠かせません。RSpec は Ruby 社で最も広く使われているテストフレームワークで、BDD(Behavior Driven Development)を実現するための構文が豊富に用意されています。RSpec の基本構文は describe と it で構成され、テスト対象の振る舞いを自然言語で記述できます。
例として、シンプルな Calculator クラスをテストするコードを示します。
RSpec.describe Calculator do
describe "#add" do
it "二つの数を足し合わせる" do
calc = Calculator.new
expect(calc.add(2, 3)).to eq(5)
end
end
end
このように、RSpec はテストケースを読みやすく、保守性の高いコードを書くためのツールです。
should vs expect の違い
RSpec では昔から should と expect の二つのマッチャー構文が存在します。should はオブジェクトに対して直接呼び出すスタイルで、expect は expect(object) の形で呼び出します。
近年は should が非推奨となり、expect が推奨されています。理由は以下の通りです。
- 読みやすさ:
expect(...).toの方が自然言語に近い。 - テストの可読性:
expectはメソッドチェーンが明確で、エラー時に原因が追いやすい。 - 将来の互換性:RSpec の新機能は
expectに合わせて実装される。
実際に書き換えると、先ほどの例は次のようになります。
RSpec.describe Calculator do
describe "#add" do
it "二つの数を足し合わせる" do
calc = Calculator.new
expect(calc.add(2, 3)).to eq(5)
end
end
end
このように、expect を使うことでテストコードがより一貫性を持ち、将来の保守が楽になります。
Stub と Mock の使い分け
テストでは外部依存を切り離すために Stub と Mock を使います。両者は似ているようで、目的が異なります。
Stub
Stub は「メソッドの戻り値を固定する」だけで、呼び出し回数や引数の検証は行いません。主に外部サービスやデータベースへのアクセスを簡略化するために使われます。
allow(User).to receive(:find).with(1).and_return(user_stub)
Mock
Mock は「メソッドが呼び出されること自体を検証する」ために使われます。呼び出し回数、引数、戻り値をすべて指定でき、テストの期待値を厳密に定義します。
expect(User).to receive(:find).with(1).and_return(user_stub)
実際のテストでは、外部依存を Stub で切り離し、内部ロジックの呼び出しを Mock で検証するパターンが多いです。
FactoryBot でデータ生成
テストデータを手動で作成するのは手間がかかります。FactoryBot は「ファクトリ」を定義して、必要なオブジェクトを簡単に生成できるツールです。以下は User モデルのファクトリ例です。
FactoryBot.define do
factory :user do
name { "テストユーザー" }
email { "test@example.com" }
password { "password" }
end
end
テスト内では次のように呼び出します。
let(:user) { create(:user) }
FactoryBot を使うことで、テストデータの一貫性と再利用性が向上し、テストコードが読みやすくなります。
BDD でテストを書く
Behavior Driven Development(BDD)は「振る舞い」を中心に設計・テストを行う手法です。RSpec は BDD を実現するために設計されており、describe と context を使って「何が起きるか」を自然言語で記述します。
RSpec.describe User, type: :model do
context "有効な属性を持つとき" do
it "保存できる" do
expect(create(:user)).to be_valid
end
end
context "メールアドレスが無いとき" do
it "無効になる" do
user = build(:user, email: nil)
expect(user).not_to be_valid
end
end
end
このように、テストは「ユーザーが有効な属性を持つときは保存できる」「メールアドレスが無いときは無効になる」といった振る舞いを明確に表現します。BDD を採用することで、開発者とテスター、さらには非技術者間で共通の理解を得やすくなります。
コメント
コメントを投稿