ホーム › ブログ › PHP・Laravelの保守・バージョンアップ › テストの無い古い PHP に最初に入れるテスト——全部は書かない

PHP・Laravelの保守・バージョンアップ

テストの無い古い PHP に最初に入れるテスト——全部は書かない

結論から書くと、テストの無い古い PHP のシステムに最初に入れるのは、「今と同じ動きをしているか」を確かめるテストを、止まると困る処理から少しだけ です。網羅率は目標にしません。順番は次の3つです。

  1. 全ファイルの構文チェック
  2. 主な画面が表示されるかの確認(スモークテスト)
  3. 計算や帳票の出力を、今の結果で固定するテスト

この3つがあるだけで、PHP のバージョンアップや依存パッケージの更新、小さな修正の前後で「壊していない」ことを、毎回同じ手順で確かめられるようになります。

なぜ全部は書かないのか

古いシステムのコードは、テストを書きやすい形になっていないことがあります。グローバル変数に頼る処理、データベースに直接つながった関数、途中で exit する画面などです。これらに単体のテストを書こうとすると、テストのためにコードを分解する必要が出てきます。テストが無い状態でコードを分解するのは、それ自体が壊すリスクのある変更です。

また、最初の目的は品質を保証することではありません。変更の前後で動きが変わっていないことを確かめる ことです。そのためには、外から見た結果(画面の表示、出力されるファイル、データベースに書かれる値)を確認するテストのほうが、少ない手間で効果が出ます。

もう1つ大事なのは、このテストが確かめるのは「正しいか」ではなく「今と同じか」だという点です。今の動きに不具合が含まれていても、まずはそのまま固定します。不具合を見つけたら記録して、直すかどうかは業務の担当者と相談します。

1本目: 全ファイルの構文チェック

最初は、テストを書かずにできる確認です。PHP の -l オプションは、公式のマニュアルのとおり、コードを実行せずに構文だけを確かめます。

find . -name '*.php' -not -path './vendor/*' -print0 | xargs -0 -n1 php -l

これを 移行先のバージョンの PHP で 実行すると、そのバージョンで使えなくなった書き方を見つけられます。たとえば $array{0} のような波かっこでの配列の参照は、PHP 8.0 で削除されたので、構文チェックの段階でエラーとして出てきます。

ただし、構文チェックで分かるのは書き方の問題だけです。削除された関数を呼んでいる箇所や、動きが変わった比較は、実行してみないと分かりません。そこで次の2つが必要になります。

2本目: 主な画面が表示されるかの確認

次は、止まると困る画面の一覧を作り、それぞれが表示されることを確かめるスクリプトです。ログイン、一覧、登録、帳票の出力など、業務の入口になる画面を選びます。最初は、止まると業務が回らなくなる画面だけで構いません。

#!/bin/bash
# urls.txt に「パス 画面に必ず出る文字列」を1行ずつ書く
BASE=http://localhost:8080
fail=0
while read -r path expect; do
  body=$(curl -s -w '\n%{http_code}' "$BASE$path")
  code=$(printf '%s' "$body" | tail -n1)
  if [ "$code" != "200" ] || ! printf '%s' "$body" | grep -q "$expect"; then
    echo "NG $path ($code)"
    fail=1
  fi
done < urls.txt
exit $fail

ステータスコードだけでなく、画面に必ず出る文字列(見出しや項目名)も確かめるのがポイントです。エラーの画面でも 200 を返すシステムがあるからです。実行の後は、エラーログに新しい行が増えていないかも見ます。

ログインが必要な画面は、検証環境にテスト用の利用者を作って確認します。本番のデータと本番の環境では実行しません。 登録の画面などは、表示の確認にとどめ、送信までは自動で行わないほうが安全です。

Laravel のシステムであれば、同じことを HTTP テストで書けます。$this->get('/') で画面を取得し、assertStatus(200) で確かめる形です。

3本目: 計算と帳票の出力を固定する

最後は、金額の計算、締め日の処理、帳票の出力など、結果が明確で、間違えたときの影響が大きい処理 です。入力を与えて、今の出力をそのまま「期待する結果」として保存し、以後はそれと同じかを確かめます。特性テスト、あるいはゴールデンマスターと呼ばれる方法です。

PHPUnit で書くと、次のような形になります。

<?php
use PHPUnit\Framework\TestCase;

final class InvoiceTest extends TestCase
{
    public function testInvoiceOutputIsUnchanged(): void
    {
        $input = json_decode(file_get_contents(__DIR__ . '/fixtures/invoice_input.json'), true);
        $expected = file_get_contents(__DIR__ . '/fixtures/invoice_expected.txt');

        $this->assertSame($expected, render_invoice($input));
    }
}

入力は、代表的な例に加えて、例外的な例を選びます。端数の処理、月末や締め日をまたぐ日付、特別な扱いの取引先などです。本番のデータから作る場合は、個人情報を伏せた値に置き換えます。

PHPUnit は、バージョンごとに必要な PHP のバージョンが決まっています。公式のサポート表では、たとえば PHPUnit 9 は PHP 7.3 以上、PHPUnit 10 は PHP 8.1 以上です。古い PHP で動いているシステムでは、その PHP で動く版を選びます。Composer を使っていれば、開発用の依存として入れます。

composer require --dev phpunit/phpunit

テストを増やすタイミング

最初の3つを入れたら、あとは変更のたびに少しずつ増やします。

  • 不具合を直すとき。 直す前に、その不具合を再現するテストを1本書きます。直した後に通れば、同じ不具合の再発も防げます。
  • バージョンアップの前。 確認項目のうち、自動にできるものをスモークテストに足します。
  • よく変更する機能。 変更のたびに手で確認している処理は、テストにする効果が大きい処理です。

すべてを自動にする必要はありません。画面の見た目や、外部のサービスとの連携など、自動にしにくい確認は手順書のまま残し、テストと手順書の両方で確認します。テストのコードや入力データの作成には AI も使えますが、何を確かめるべきかは業務を知る人が決めます。仕様書の無いコードの動きを AI で整理し、テストで固定する手順は「生成 AI で仕様書のないレガシーコードから仕様を復元する手順」で説明しています。

このテストが最も役に立つのは、PHP やフレームワークのバージョンを上げるときです。進め方は「Laravel バージョンアップの手順と、実際に詰まるポイント」をご覧ください。

h-system でできること

h-system では、テストの無い古い PHP・Laravel のシステムについて、止まると困る処理の洗い出しから、構文チェック、スモークテスト、出力を固定するテストの整備までを開発者本人がお引き受けしています。バージョンアップや改修の前の準備として、テストの整備だけをご依頼いただくことも可能です。初回のご相談と概算のお見積りは無料で、詳細な調査は有償です。範囲と費用は着手前にご案内します。

TOP