なぜモックを使うのか
テストを書くとき、メールの送信・キャッシュの読み書き・外部APIの呼び出しなど、実際には実行したくない処理があります。
こうした処理を「本物のふりをする偽物」で置き換えることをモックと呼びます。
モックを使うメリットは次のとおりです。
- テストが速い — 外部サービスや重い処理を実行しないため、テストがすぐ終わる
- テストが安定する — 外部サービスの状態に左右されず、常に同じ結果になる
- テストの範囲が明確になる — 1つのクラスやメソッドだけを検証できる
Laravelはイベント・ジョブ・ファサードなどのモックをすぐに使えるヘルパーを提供しています。
内部では Mockery を使っており、複雑なセットアップなしに利用できます。
モックオブジェクト
サービスコンテナ経由で注入されるオブジェクトをモックするには、モックインスタンスをコンテナへバインドします。
こうすると、コンテナはオブジェクトを生成する代わりにモックインスタンスを使います。
mock() メソッド
Laravelのテストケース基底クラスが提供する mock() メソッドを使うと、上記と同等の処理をより簡潔に書けます。
partialMock() メソッド
オブジェクトの一部のメソッドだけをモックしたい場合は partialMock() を使います。
モックしていないメソッドは通常通り実行されます。
spy() メソッド
スパイはモックに似ていますが、コードの実行後にインタラクションを検証する点が異なります。
モックが「このメソッドが呼ばれるはずだ」と事前に設定するのに対し、スパイは「このメソッドが呼ばれたかどうか」をあとから確認します。
ファサードのモック
ファサードは通常の静的メソッド呼び出しと異なり、モックができます。
依存性注入と同等のテスタビリティを持ちながら、簡潔な構文で書けます。
例として、キャッシュを使うコントローラーを考えます。
Cache ファサードの get メソッドをモックするには expects() を使います。
Request ファサードはモックしないでください。その代わりに、get や post などのHTTPテストメソッドに入力値を渡してください。同様に、Config ファサードをモックする代わりに Config::set() をテスト内で呼び出してください。
ファサードスパイ
ファサードをスパイで監視するには、対応するファサードの spy() メソッドを呼び出します。
スパイはコードが実行された後にインタラクションを検証したいときに便利です。
時間の操作
テストで時間に依存するロジックを検証するとき、now() や Carbon::now() が返す時刻を変更できると便利です。
Laravelのフィーチャーテスト基底クラスには、時間を操作するためのヘルパーが用意されています。
travel() — 時間を移動する
クロージャを使った時間移動
時間移動メソッドにクロージャを渡すと、指定した時刻で時間を止めてクロージャを実行し、完了後に元の時刻に戻ります。
freezeTime() — 時間を止める
freezeTime() は現在時刻を固定します。freezeSecond() は現在時刻を秒の先頭で固定します。
実用例:非アクティブなスレッドのロック
時間操作は、一定期間操作がないと投稿がロックされるフォーラムのような機能のテストに役立ちます。
travel() などの時間操作メソッドは、フィーチャーテスト(Tests\TestCase を継承するクラス)でのみ使えます。PHPUnitの基底 TestCase では使えません。
メソッド一覧
モック関連
時間操作関連