IT-Q

RefreshDatabase が速いのはなぜですか。それが使えない場面はありますか。

スキーマが最新ならマイグレーションを流し直さず、各テストをトランザクションで囲んで終了時にロールバックしているためです。トランザクションを直接検証したい場合は使えません。

面接官が見ているのは仕組みを知っているか。

これは「Laravel でテストを書くときの方針として妥当なのはどれですか。」への追撃質問です。

よくある答えと、面談でどう見られるか

  • 各テストをトランザクションで囲みロールバックしているから。別コネクションからは変更が見えない
    その通りです。ブラウザテストのように別プロセスから DB を見る場合や、テスト対象がコミットに依存する場合には使えません。
  • DB を使わずメモリ上で動くから
    実際に DB を使います。速いのはロールバックで済ませているからです。
  • マイグレーションを毎回流し直しているから
    それは DatabaseMigrations の方で、こちらは遅いです。
  • テーブルを truncate しているから
    惜しいですが、truncate よりトランザクションのロールバックの方が速い、というのが要点です。

面接官は何を見ているか

  • トランザクションで囲んでロールバックしていると説明できた
  • 毎回マイグレーションを流し直すより速い理由を言えた
  • トランザクションを使う処理との相性問題に触れた

模範解答

スキーマが最新であればマイグレーションを流し直さず、各テストをトランザクションで囲んで実行しているからです。終了時にロールバックされます。毎回テーブルを作り直す DatabaseMigrations や、毎回 truncate するDatabaseTruncation は、公式が「どちらも著しく遅い」と書いています。

使えない場面は2つ。1つはブラウザテストで、公式に「Dusk のテストで RefreshDatabase を使ってはいけない」と明記されています。トランザクションは HTTP リクエストをまたげないからです。Dusk では DatabaseMigrations か DatabaseTruncation を使います(毎回作り直すより truncate の方が速い)。もう1つは、テスト対象のコード自体がコミットの完了に依存している場合です。

もう1点、実務で刺さるのが「このトレイトを使っていないテストが入れたレコードはDB に残り続ける」という副作用です。ロールバックされるのは、あくまでトレイトを使っているテストの中の変更だけです。