環境
Laravel 10.x(8.x以上
Github Actions
手法1 DatabaseTransactionsを利用する
Laravelではテスト実行後にDBをクリーンにするのにuse RefreshDatabase;
が使われる事が多々あります。
しかし、DBを一度消して再作成するため、時間が結構かかります。
テストがPKに依存していないならuse DatabaseTransactions
を利用すると高速化が図れます。
これはテスト実行時にトランザクションを貼り、終わったらロールバックしてくれます。
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
use DatabaseTransactions; //追記
}
手法2 paratestを利用する
8.x以降では、php artisan test --parallel
でプロセス数に応じた並列テストが実行できます。
Github Actionsではデフォルトでprivateリポジトリだと2プロセス利用できる。
それだけで単純計算実行時間が1/2になる。
インストール
composer require brianium/paratest --dev
AppServiceProviderにてパラレル実行時にsetUpTestDatabaseしたらseedまでするようにしています。
ParallelTesting::setUpTestDatabase(function (string $database, int $token) {
Artisan::call('migrate', ['--seed' => true]);
});
注意点としてはdatabaseの権限ないと、データベース作成できないエラーになるのでrootなりにしておくと良いかと。
手法3 GitbhubActionsでMatrixを利用して並列job実行でテストする
単一のジョブ定義で変数を使用して、変数の組み合わせに基づいて複数のジョブ実行できます。
やり方は完全にこちらの記事の通りですが、
分割数とidを定義して、その数にテストを分割しています
matrix:
parallelism: [5]
id: [0,1,2,3,4]
~ /// ~~
- name: Run Tests
run: |
find tests/ -name '*Test.php' | sort | awk "NR % ${{ matrix.parallelism }} == ${{ matrix.id }}" | xargs php ./create_multithread_phpunit_xml.php
./vendor/bin/phpunit --configuration ./ci_phpunit.xml
結論
手法1 ~ 3を組み合わせる
jobで並列にして、その中でプロセスを複数でテストする
テスト自体は30分から3分程度に短縮できました。composerやmysqlコンテナなどのセットアップいれても全体で5分くらいのワークフローに短縮できました
matrix:
parallelism: [5]
id: [0,1,2,3,4]
~ /// ~~
- name: Run Tests
run: |
find tests/ -name '*Test.php' | sort | awk "NR % ${{ matrix.parallelism }} == ${{ matrix.id }}" | xargs php ./create_multithread_phpunit_xml.php
php artisan test --parallel --configuration ./ci_phpunit.xml