RefreshDatabase が速いのはなぜですか。それが使えない場面はありますか。
スキーマが最新ならマイグレーションを流し直さず、各テストをトランザクションで囲んで終了時にロールバックしているためです。トランザクションを直接検証したい場合は使えません。
面接官が見ているのは仕組みを知っているか。
これは「Laravel でテストを書くときの方針として妥当なのはどれですか。」への追撃質問です。
よくある答えと、面談でどう見られるか
- 各テストをトランザクションで囲みロールバックしているから。別コネクションからは変更が見えない
その通りです。ブラウザテストのように別プロセスから DB を見る場合や、テスト対象がコミットに依存する場合には使えません。 - DB を使わずメモリ上で動くから
実際に DB を使います。速いのはロールバックで済ませているからです。 - マイグレーションを毎回流し直しているから
それは DatabaseMigrations の方で、こちらは遅いです。 - テーブルを truncate しているから
惜しいですが、truncate よりトランザクションのロールバックの方が速い、というのが要点です。
面接官は何を見ているか
- トランザクションで囲んでロールバックしていると説明できた
- 毎回マイグレーションを流し直すより速い理由を言えた
- トランザクションを使う処理との相性問題に触れた
模範解答
スキーマが最新であればマイグレーションを流し直さず、各テストをトランザクションで囲んで実行しているからです。終了時にロールバックされます。毎回テーブルを作り直す DatabaseMigrations や、毎回 truncate するDatabaseTruncation は、公式が「どちらも著しく遅い」と書いています。
使えない場面は2つ。1つはブラウザテストで、公式に「Dusk のテストで RefreshDatabase を使ってはいけない」と明記されています。トランザクションは HTTP リクエストをまたげないからです。Dusk では DatabaseMigrations か DatabaseTruncation を使います(毎回作り直すより truncate の方が速い)。もう1つは、テスト対象のコード自体がコミットの完了に依存している場合です。
もう1点、実務で刺さるのが「このトレイトを使っていないテストが入れたレコードはDB に残り続ける」という副作用です。ロールバックされるのは、あくまでトレイトを使っているテストの中の変更だけです。