第15回: Repository層のテスト戦略 — 「Eloquentのモック」だけで本当の動作を守れますか?

章: 第7章: テスト拡張と品質自動化

Repository層は永続化ロジックの契約層です。上位層がRepositoryの返却仕様に依存するため、返却値の型やフィルタリングの挙動をテストで固定することが重要です。

モック中心になりすぎると、実際のクエリが正しく機能するか検証できなくなります。SQLiteやインメモリデータベースを使った実データベーステストを組み合わせることで、信頼性の高い検証になります。

なぜRepositoryテストが重要なのか

Repositoryをテストしない場合、次のリスクが残ります。

  • findById() が null を返すべきケースで実幸を返す
  • findByEmail() の大文字小文字比較が実際のDBSで差异が出る
  • 有効期限条件のフィルタリングが実際のタイムゾーン差异で崩れる

チェックポイント: Repositoryテストは「返却値の仕様」を固定するテストです。モックではなく、実際のDBAを使って検証することで初めて価値が出ます。

モック vs 実データベース

観点 モック中心 実データベーステスト
SQLの正種性 検証不可 検証可能
実行速度 高速 少し遺る
信頼性 低い(実題DBと差异リスク) 高い
おすすめ サービス層のテスト Repository層のテスト

実装例


<?php
it('IDでユーザーを取得できる', function () {
    $user = User::factory()->create();
    $repo = app(App\Repositories\UserRepository::class);

    $found = $repo->findById($user->id);

    expect($found)->not->toBeNull();
    expect($found->id)->toBe($user->id);
});

まとめ & 次のステップ

  • Repositoryテストはインターフェースの契約を固定することが目的 ― 実際のDBAAで検証する
  • SQLiteのインメモリ DB (DB_CONNECTION=sqlite + :memory:) で高速な実データベーステストが実現できる
  • findById(null)findByEmail('') のエッジケースを心づけると上位層のバグを減らせる
  • Repositoryテストを通じた仕様変更は、天面ライブラリから自分たちの仕様への表明になる

次回は 第16回: Contractテストで実装差し替えに備える で、複数実装が同じ挙動を守ることを保証するテスト設計を学びます。最初は少し難しく見えても、順番に確認すればちゃんと身についていきます。

今日の記事のポイント

Repository層は永続化ロジックの契約を固定するテストが有効です。

この記事が大事な理由

上位層がRepositoryの振る舞いに依存するため、返却仕様のブレを防ぐ必要があるからです。

ここは「どの場面で使うのか」を結びつけると理解しやすくなります。実際のコードを動かしながら、少しずつ慣れていきましょう。

よくあるつまずき

モック中心にしすぎず、SQLiteなどで実DB寄りの検証も入れていきましょう。

「Repository層のテスト戦略」でつまずくときは、知識不足というより「確認の順番」が曖昧なことが多いです。最初に観点を固定すると、理解が一気に進みやすくなります。

整理しやすい観点は次の3つです。

  • 何を守るテストかを明確にする: 仕様固定か実装詳細かを先に決める
  • テスト粒度を揃える: FeatureとUnitの責務を混ぜない
  • 壊れやすい箇所から優先する: 変更頻度の高いユースケースに先に網をかける

小さく検証するときは、次の順番で進めると詰まりにくくなります。

1. 「Repository層のテスト戦略」に直結する主要ケースを3件だけ先に作る

2. 失敗ケースを1件追加し、期待するエラーを明示する

3. リファクタ後に同じテストが通ることを確認する

「Repository層のテスト戦略」は、守りたい仕様を言語化してから書くと品質が安定します。

実際のコードのサンプル

まずは最小構成で動きを確認していきましょう。


<?php
it('IDでユーザーを取得できる', function () {
    $user = User::factory()->create();
    $repo = app(App\Repositories\UserRepository::class);

    $found = $repo->findById($user->id);

    expect($found)->not->toBeNull();
    expect($found->id)->toBe($user->id);
});

この記事で身についたこと

Repository層は永続化ロジックの契約を固定するテストが有効であることがわかりました。

今日のまとめ

Repository層のテスト戦略は、Laravelをより深く使うための大切な知識です。完璧を目指しすぎず、手を動かしながら少しずつ使える形にしていきましょう。

「Repository層のテスト戦略」を学ぶときは、実装前に「何を楽にしたいのか」「どこで失敗しやすいか」「確認結果をどう残すか」を先に言葉にしておくと理解が安定します。短いメモでも、次回の見直し時に判断材料として大きく効いてきます。

「Repository層のテスト戦略」を実務で使うときは、設定値だけでなく運用時の確認観点までセットで決めておくと判断が安定します。特に「変更前に確認する項目」「変更後に監視する項目」「問題が起きたときの戻し方」を先に整理しておくと、手戻りを減らしやすくなります。

学習メモ

  • サンプルをそのまま実行したあと、値や条件を1つだけ変えて結果の違いを見ていきましょう。
  • 「Repository層のテスト戦略」について、今日の気づきを1行で残しておくと次回の理解がかなり速くなります。
  • 実務に置き換えるならどの機能に使えるかを1つ書き出しておくと、学びが定着しやすくなります。

Related Articles