3
Help us understand the problem. What are the problem?
Organization

CakePHP4.3のフィクスチャファクトリとプラグインのユニットテスト

引き続き、baserCMS5の開発にてCakePHP2系から4系への移行を進めています。

CakePHP4.3 より、これまでのフィクスチャマネージャーが非推奨になり、フィクスチャファクトリの利用が推奨されているようです。
色々と仕組みがややこしく、ドキュメントが少ないので記録しておきます。

従来は、テスト実行時にテーブルの作成とデータ登録がされていたのですが、フィクスチャマネージャーを利用しなくなった事により、テーブルの作成処理が tests/bootstrap.php でのマイグレーションでの生成に移行となっている様子。
つまり、 bootstrap.php にて、マイグレーションを実行しないとテーブルが作成されない仕様。

まず、マイグレーションは tests/bootstrap.php 次のように実行します。

use Migrations\TestSuite\Migrator;
// マイグレーションが一つの場合
new Migrator->run(['plugin' => 'BaserCore']);
// マイグレーションが複数の場合
(new Migrator())->runMany([
    ['plugin' => 'BaserCore'],
    ['plugin' => 'BcFavorite']
]);

bootstrap の実行仕様

となると、プラグインのマイグレーションは、プラグイン内の bootstrap.php で実行したいところだが、 bootstrap.php の実行は、カレントディレクトリ内の tests/bootstrap.php を利用する仕様となっているため、プラグイン内の bootstrap.phpを実行するは、プラグインディレクトリに移動するか、 --bootstrap オプションを指定しなければならない。 めんどい。

# プラグインディレクトリに移動する場合
cd plugins/baser-core
../../vendor/bin/phpunit
# アプリケーションルートでオプションを指定する場合
vendor/bin/phpunit --bootstrap plugins/baser-core/tests/bootstrap.php

 

プラグイン単独でユニットテストを実行する

その上で、プラグイン単独でユニットテストを実行する方法を調べてみた。
まず、プラグインディレクトリ内に phpunit.xml.dist を作成する。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
         colors="true"
         bootstrap="tests/bootstrap.php"
>
    <php>
        <ini name="memory_limit" value="-1"/>
        <ini name="apc.enable_cli" value="1"/>
    </php>
    <testsuites>
        <testsuite name="BcFavorite">
            <directory>tests/TestCase</directory>
        </testsuite>
    </testsuites>
    <extensions>
        <extension class="Cake\TestSuite\Fixture\PHPUnitExtension"/>
    </extensions>
    <coverage>
        <include>
            <directory suffix=".php">src/</directory>
        </include>
    </coverage>
</phpunit>

次に、tests/bootstrap.php を作成する。

use Migrations\TestSuite\Migrator;

$findRoot = function($root) {
    do {
        $lastRoot = $root;
        $root = dirname($root);
        if (is_dir($root . '/vendor/cakephp/cakephp')) {
            return $root;
        }
    } while($root !== $lastRoot);
    throw new Exception("Cannot find the root of the application, unable to run tests");
};
$root = $findRoot(__FILE__);
unset($findRoot);
chdir($root);

require_once $root . '/vendor/autoload.php';
require $root . '/config/bootstrap.php';

(new Migrator())->runMany([
    ['plugin' => 'BaserCore'],
    ['plugin' => 'BcFavorite']
]);

ユニットテストの実行を composer 経由にする場合は、 composer.json に次を追記する。

    "scripts": {
        "test": [
            "Composer\\Config::disableProcessTimeout",
            "../../vendor/bin/phpunit --colors=always"
        ]
    }

ただ、この場合、プラグインディレクトリ内で実行する事が前提となる。
GitHubActionsなどのCIで、docker を使いつつ(baserCMS5の開発の場合)自動化するためには、yml ファイルにて、 --workdir オプションを指定して次にように記述する必要がある。
(プラグインではなくアプリケーションルート側で設定する場合)

docker exec --workdir /var/www/html/plugins/bc-favorite [コンテナ名] composer run-script test

なお、特定ファイルを指定する場合のユニットテストのコマンドは次のようになる。

cd plugins/bc-favorite
../../vendor/bin/phpunit tests/TestCase/Controller/Api/FavoritesControllerTest.php 
  • プラグインフォルダに移動しなければならない
  • 上位階層の実行ファイルを指定しなければならない
  • パス指定がコンテンツルートではなくプラグインルートからのパスとなる(最近のIDEでは、指定ファイルのコンテンツルートからのパスをコピーする機能があるがそれが利用できない)

めんどい。

 

baserCMSコア、コアプラグイン開発の最適解

特定ファイルのパス指定が特にめんどいので、baserCMS5の開発では、ルート直下の phpunit.xml.dist にテスト対象のプラグインを全て定義し、ルート直下の tests/bootstrap.php に、対象プラグインのマイグレーションを全て記述することにした。

 
baserCMSの CakePHP4系化の開発プロジェクトのレポジトリはこちら。
https://github.com/baserproject/ucmitz
(協力者募集しています)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?