RSpec マッチャー を使うことで、テストコードの可読性を高め、効率的に動作確認ができます。本記事では、基本のマッチャーから応用テクニックまで、実践例を交えながら徹底解説します。
基本のマッチャー
比較系マッチャー
eq, eql, equal, be の違い
eq
: 値が等しいeql
: 値と型が等しいequal
,be
: オブジェクトIDが同じ
describe '比較系マッチャーの例' do
it 'eq と eql の違い' do
expect(1).to eq(1) # 値が等しい
expect(1).to eql(1) # 値と型が等しい
expect(1).not_to equal(1.0) # オブジェクトIDが異なる
end
end
真偽値系マッチャー
be_truthy, be_falsey, be_nil の使い分け
be_truthy
:nil
以外の全ての値be_falsey
:nil
またはfalse
be_nil
:nil
のみ
describe '真偽値系マッチャーの例' do
it 'be_truthy と be_falsey' do
expect(true).to be_truthy
expect(false).to be_falsey
expect(nil).to be_falsey
end
end
コレクション系マッチャー
配列の検証
include, match_array, contain_exactly の使い分け
describe 'コレクション系マッチャーの例' do
it 'include の例' do
array = [1, 2, 3]
expect(array).to include(1)
expect(array).to include(1, 3)
end
end
Rails特有のマッチャー
ActiveRecord関連
RailsにはActiveRecordモデルを効率よくテストするためのマッチャーが用意されています。
以下は バリデーション、スコープ、アソシエーション のテスト例です。
バリデーションのテスト
バリデーションのテストには be_valid
を使用しますが、より詳細なテストには validate_presence_of
や validate_uniqueness_of
を使います。
describe User, type: :model do
it '名前、メールアドレスがある場合、有効であること' do
user = User.new(name: 'Alice', email: 'test@example.com')
expect(user).to be_valid
end
it '名前がない場合、無効であること' do
user = User.new(name: nil, email: 'test@example.com')
expect(user).not_to be_valid
expect(user.errors[:name]).to include("can't be blank")
end
it 'メールアドレスの一意性を検証する' do
User.create!(name: 'Bob', email: 'unique@example.com')
duplicate_user = User.new(name: 'Alice', email: 'unique@example.com')
expect(duplicate_user).not_to be_valid
end
end
スコープのテスト
Railsのスコープ (scope
) をテストする場合、match_array
を使って期待する配列の順序を無視して比較できます。
describe User, type: :model do
before do
@active_user = User.create!(name: 'Active', active: true)
@inactive_user = User.create!(name: 'Inactive', active: false)
end
it 'active スコープは有効なユーザーのみを返すこと' do
expect(User.active).to match_array([@active_user])
end
end
アソシエーションのテスト
Railsのアソシエーション (belongs_to
, has_many
など) をテストするには、shoulda-matchers
を活用します。
describe User, type: :model do
it { should have_many(:posts) }
it { should belong_to(:company) }
end
—
カスタムマッチャーの作成
RSpecには用意されていない オリジナルの検証ロジック を追加する場合、カスタムマッチャーを作成できます。
これにより、共通の検証を使い回す ことが可能です。
数値の偶数チェック (シンプルな例)
RSpec::Matchers.define :be_even do
match do |actual|
actual.even?
end
failure_message do |actual|
"expected #{actual} to be even"
end
end
describe 'カスタムマッチャーの例' do
it '偶数の検証' do
expect(4).to be_even
expect(3).not_to be_even
end
end
複雑なカスタムマッチャー (レスポンスのJSON構造検証)
RSpec::Matchers.define :have_json_key do |expected_key|
match do |response|
json = JSON.parse(response.body)
json.key?(expected_key)
end
failure_message do |response|
"expected JSON response to have key '#{expected_key}'"
end
end
describe 'APIレスポンスのテスト' do
it 'name キーを含むこと' do
get '/api/v1/users/1'
expect(response).to have_json_key('name')
end
end
—
マッチャー活用のベストプラクティス
マッチャーを効率的に使うことで、テストの 読みやすさ、保守性、パフォーマンス を向上させられます。
読みやすさ重視のテスト設計
- テストの意図が明確に伝わるように、マッチャーは具体的な名前を使う
- expect ブロックを1つのテスト内に 1つだけ 記述することで、失敗箇所を特定しやすくする
カスタムマッチャーの共通化
- 複数のテストで同じ検証を使う場合、カスタムマッチャーにまとめることで 重複を排除
- RSpecの support ディレクトリ を活用して、共通化したカスタムマッチャーを読み込む
パフォーマンスの考慮
- 不要なクエリ発行を防ぐために、 include や joins をテスト対象のスコープに含める
- before ブロックを活用 して、重複するセットアップを最適化
この記事を通して、RSpecのマッチャーをより深く理解し、テストの品質と効率を大幅に向上させる方法を身につけましょう!
まとめ
マッチャーを理解することで、テストの品質と効率が向上します。RSpecの強力な機能をフル活用して、より良いテストを書きましょう。
コメント