プラグイン(拡張アプリ)のテスト
自作プラグイン(拡張アプリ)に PHPUnit のテストを書き、変更しても壊れていないことを自動で確かめられるようにするための入門ガイドです。
PHPUnit とはPHPのコードをテストするための公式のテストフレームワークです。
このガイドで何ができるようになるか
プラグインは a-blog cms 本体のクラスや DB に触れるため、これまでは「本体を丸ごと用意しないとテストできない」のが実情でした。テスト基盤 ablogcms/testing-framework を使うと、プラグイン単体のリポジトリのまま、本体コアに触れる処理(Services / Validator / Hook や DB を伴う処理)をテストできます。本体のソースや難読化イメージを手元に持っていなくても、composer require --dev して phpunit を叩くだけでテストが回ります。
用意するものは大きく 3 つです。用途に応じて必要なものだけ使います。
提供物 | 入手先 | 役割 |
|---|---|---|
| Packagist( | PHPUnit の基底クラス・Seeder・DB 作成コマンド・PHPStan 設定を提供 |
| 本体同梱の実行環境。 | |
| Packagist( | テスト・PHPStan・CI が設定済みのプラグインひな型 |
appleple/acms は開発・CI 用途のイメージです。 本番運用には使わないでください。
前提
Docker(本体を含む環境の中でテストを実行するため)
テストを書くプラグインが名前空間規約
Acms\Plugins\{Name}\に沿っていること
テストは a-blog cms 本体を含む環境の中で実行します。ローカルに本体一式が入った Docker コンテナがある場合はそれを使えますし、無ければ次章のスケルトン(同梱イメージ appleple/acms を参照)が最短です。
最短ルート: スケルトンから始める
ゼロから 1 つプラグインを作るなら、テスト・PHPStan・CI が最初から設定されたひな型を使うのが早いです。
composer create-project ablogcms/plugin-skeleton my-plugin
cd my-plugin
docker compose up -d
docker compose exec acms bash -lc "composer install && vendor/bin/acms-create-database && vendor/bin/phpunit"
# → サンプルテストが緑になれば環境は完成この時点で tests/Unit と tests/Integration にサンプルが入っています。あとは src/ に自分のコードを、tests/ に対応するテストを足していくだけです。書き方は テストの書き方 を参照してください。
既存のプラグインに導入する
すでにあるプラグインへ後から組み込む場合の手順です。追加するファイルは 2 つ(composer.json への追記と phpunit.xml.dist)だけで、プラグインごとに tests/bootstrap.php を書く必要はありません。
1. composer.json に追記する
{
"require-dev": {
"ablogcms/testing-framework": "3.2.*"
},
"autoload": { "psr-4": { "Acms\\Plugins\\Foo\\": "src/" } },
"autoload-dev": { "psr-4": { "Acms\\Plugins\\Foo\\Tests\\": "tests/" } }
}
バージョンは、テストしたい a-blog cms のマイナーバージョンに合わせます(3.2 系なら 3.2.*、3.3 系なら 3.3.*)。^3.2 は 3.3 系まで拾ってしまうため使いません(理由は CI と複数バージョン検証 を参照)。
2. phpunit.xml.dist を置く
起動処理はテスト基盤に同梱の共有エントリにまとまっているので、bootstrap でそれを直接指します。
<?xml version="1.0"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/ablogcms/testing-framework/bootstrap.php"
colors="true"
cacheDirectory=".phpunit.cache"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory>tests/Integration</directory>
</testsuite>
</testsuites>
<php>
<!-- a-blog cms 本体の場所。環境(Docker コンテナ内のパス等)に読み替える -->
<env name="ACMS_ROOT" value="/var/www/html"/>
</php>
</phpunit>ACMS_ROOT には本体のルートを渡します。同梱イメージ appleple/acms を使う場合は /var/www/html、本体ソースのモノレポ/作業ツリーを使う場合はそのルート(ablogcms/ を含むディレクトリ)を指定します。どちらのレイアウトでも自動判定されます。
phpunit.xml の <env> には ACMS_ROOT だけを書きます。 DB の接続情報はここに書きません。書いてしまうと後述の .env.testing 側の値が無視されるためです(環境変数は「先に設定済みの値を上書きしない」ため)。テスト用 DB の用意は次の手順を参照してください。
追加の初期化(フィクスチャ読み込みなど)が必要なときだけ、自前の tests/bootstrap.php で共有エントリを require してから足します(置き換えではなく上乗せ)。
<?php
// tests/bootstrap.php(カスタムが必要なときだけ)
require_once __DIR__ . '/../vendor/ablogcms/testing-framework/bootstrap.php';
// ここに独自の初期化を足す
3. テスト用データベースを用意する(統合テストを書く場合)
統合テスト(DatabaseTestCase)は実際の DB に接続します。単体テストしか書かないなら、この手順は不要です。
用意するものは 3 つです。
MySQL(互換)サーバを起動する。同梱イメージ
appleple/acmsを docker compose で使う場合は、dbサービスがこれにあたります。テスト専用のデータベースを 1 つ用意する(本番とは必ず分けます)。docker compose なら
dbサービスのMYSQL_DATABASE、手動ならCREATE DATABASEで作ります。vendor/bin/acms-create-databaseはその中にテーブルを作るだけで、データベース自体は作りません。接続情報を渡す。方法は 2 通りで、どちらも
ACMS_DB_*を使います。
方法 A: 本体の .env.testing(ACMS_ROOT 直下に置くファイル)
# <ACMS_ROOT>/.env.testing
ACMS_DB_HOST=db
ACMS_DB_PORT=3306
ACMS_DB_NAME=db_acms_test
ACMS_DB_USER=root
ACMS_DB_PASS=root方法 B: 環境変数(docker compose の environment や CI の env)
同じ ACMS_DB_* を環境変数で渡します。Docker で開発しているなら compose の environment に書くのが手軽です。
未指定時の既定は 127.0.0.1 / 3306 / db_acms_test / root / root です。ACMS_DB_NAME に指定した名前のデータベースが存在している必要があります。
各統合テストはトランザクション内で実行され、終了時に自動でロールバックされます。テスト用 DB にデータが残り続けることはありませんが、事故防止のため本番とは別の DB を使ってください。
4. 最初のテストを緑にする
本体を含む環境(Docker コンテナ)の中で実行します。
composer install # 依存のインストール(初回)
vendor/bin/acms-create-database # テスト用 DB のテーブル作成(統合テストの前に一度だけ)
vendor/bin/phpunit # テスト実行
acms-create-database はテスト用 DB のテーブルを無人で作成するコマンドです。統合テストを回す前に一度だけ実行します(単体テストしか書かないなら不要)。
うまくいかないときは
最初の緑にたどり着けないときに多い原因です。
症状 | 主な原因と対処 |
|---|---|
|
|
|
|
DB 接続でエラー/意図しない既定 DB につながる |
|
|
|
| 先に |
ディレクトリ構成の目安
my-plugin/
├── composer.json ← require-dev / autoload を追記
├── phpunit.xml.dist ← bootstrap は共有エントリを直接指す
├── src/ ← プラグイン本体(テスト対象)
│ ├── ServiceProvider.php
│ ├── GET/
│ ├── POST/
│ └── Services/
└── tests/
├── Unit/ ← DB 不要(TestCase)
└── Integration/ ← DB あり(DatabaseTestCase)
関連ドキュメント
テストの書き方 — 単体・統合テスト・Seeder の具体例