第18回: リファクタリングの防波堤を作る — 「テストなしでリファクタ」は冢投げです
リファクタリングは外部振る舞いを変えずに内部構造を改善することです。その「外部振る舞い」を保証するテストがなければ、リファクタ前後で振る舞いが変わっても気づけません。
現代のWeb開発者へ。基礎文法からアーキテクチャまで、体系的に学べる技術ガイド。
# User.php
public function init() {
$this->role = 'Architect';
return 'Ready to build';
}
リファクタリングは外部振る舞いを変えずに内部構造を改善することです。その「外部振る舞い」を保証するテストがなければ、リファクタ前後で振る舞いが変わっても気づけません。
カバレッジ指標は「コードが実行されたか」を測るだけで、「アサーションが正しいか」は別問題です。「if ($a > 0) を if ($a >= 0) に変更してもテストが逃げる」という状態は、Mutation Testingで初めて露呈できます。
インターフェース(Contract)を定義する目的の一つは、実装を差し替えても挙動が変わらないことの保証です。この保証をテストで固定しなければ、RedisからMemcachedへ切り替えたときにどこかで微妙な差异が発生するリスクがあります。
Repository層は永続化ロジックの契約層です。上位層がRepositoryの返却仕様に依存するため、返却値の型やフィルタリングの挙動をテストで固定することが重要です。
assertStatus(200) で満足しているテストは、「リクエストがおそらく到達した」ことを確認しているだけです。その後のDBの状態・レスポンスのJSON構造・リダイレクト先まで検証することで初めて「機能が正しく動いた」と言えます。
「同じロジックだが入力値だけ変わるテスト」が何度もコピペースされている――境界値テストでよく起きるこの状態は、Pestのデータセット機能で訐決できます。
Laravel Octaneはアプリを常駐化して後続リクエストを高速に底だけるパワーツールです。用い方を注意しないと、リクエスト間で状態が漏れる深刻な問題が起きます。「「導入したのにおかしい挙動が起きる」」の大半はこの状態漏れです。
「Unitテストが全部緑なのにリファクタ後に本番でバグが起きた」――これは、実装詳細をテストしていて、ユーザーが実際に使う流れ をテストしていなかったために起きます。
Queueのワーカーが死んでジョブが溢れている状態で、ユーザーから「メールが来ない」と見つかるまで数分かかることがあります。Laravel Horizonは、Queueの状態をリアルタイムで見るダッシュボードを提供し、そうした盲点を排除します。
外部APIへの接続が一時的に失敗したとき、ジョブがそのまま消えてしまう――これはジョブの 失敗設計がない 状態で起きる定番の事故です。「たまに失敗する」と「常に失敗する」の間にある状態を放置すると、運用後に大きな手戻りを召います。