March 18, 2022 • ☕️ 6 min read
【 環境 】
Laravel のバージョン: 8.61.1
PHP のバージョン: 8.0.16
MySQL のバージョン: 5.7.32
Laravel にてテストコードを実行する時、
「テスト実行前にコンフィグをキャッシュした時は “.env” から値を参照し、テスト実行前にコンフィグをキャッシュしなかった時は “phpunit.xml” から値を参照する」
という、知っておかないとドハマリする、なかなかに闇が深い挙動をしたりする。
例えば、以下のコード。
テストコードです。
public function testPrueba01()
{
$token = config('docurain.token');
echo "===================================" . PHP_EOL;
echo "token:{$token}" . PHP_EOL;
echo "===================================" . PHP_EOL;
}
.env を読み込んでいるコンフィグファイルです。
return [
'token' => env('DOCURAIN_TOKEN'),
];
DOCURAIN_TOKEN はアクセストークンです。ちなみに、適当に用意した値です。
DOCURAIN_TOKEN=FohVai3zei7dei8zainanuaphohqu5uz1Goh9aiy
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
上記のコードを実行する時、テストコード実行前にコンフィグをキャッシュするか、しないかで実行結果が変わってくる。
実行コマンド
php artisan config:clear | php artisan config:cache
php artisan test tests/Sample01Test.php
実行結果
===================================
token:FohVai3zei7dei8zainanuaphohqu5uz1Goh9aiy
===================================
実行コマンド
php artisan config:clear
php artisan test tests/Sample01Test.php
実行結果
===================================
token:
===================================
コンフィグをキャッシュする場合、.env 内の「DOCURAIN_TOKEN」の値を参照する。
コンフィグをキャッシュしない場合、phpunit.xml 内の 「server name=“DOCURAIN_TOKEN”」の値を参照する。
ただ、上記の場合では phpunit.xml にそんな値を設定していないので、空の値が出力されてしまう。
例えば、こんな感じ。
<php>
<server name="DOCURAIN_TOKEN" value="FohVai3zei7dei8zainanuaphohqu5uz1Goh9aiy"/>
</php>
見えようが見えまいがどうでもいい情報ならまだしも、アクセストークンとか超入れたくない。
そもそも、トークンが .env との二重管理になってしまい、その観点でも良い方法とは言い難い。
解決はできるものの、とんでもなく気持ち悪く、できれば他の方法を取りたいところだ。
他の案として、「テスト実行時は常にコンフィグをキャッシュし、.env の値をする」という方法がありはするが、テスト実行時に phpunit.xml に記述した内容を参照しないというのは、さすがにナシだろう。
テストコードを CI/CD に組み込んで実行する場合、実行コマンドはこんな感じになるかと思います。
php artisan test
ユニットテスト、機能テストで分ける場合、こんな感じ。
php artisan test tests/Unit
php artisan test tests/Feature
phpunit.xml は、こんな感じ。
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
この場合、テストコード実行の対象は、以下のディレクトリとなります。
/tests/Unit/*
/tests/Feature/*
.env から値を取得する必要があるものの、phpunit.xml にその値を書きたくない、といった情報(サービスへのアクセストークンなど)が必要なテストは、上記のディレクトリとは切り離した場所に保存する。例えば、こんな感じ。
/tests/Docurain/EstimateTestExtra.php
こういう事に気を回さないといけないケースは、おそらく外部サービスへのアクセスが必要で、その時にトークンやシークレットキーといった情報が必要になる時ぐらいかと思われます。
ただ、その場合、アクセス回数に制限があったり、アクセス数によって課金される金額が変わってきたりと、CI/CD に組み込むにはちょっと慎重にした方がいいケースが多いのではないかと思われます。
なので、CI/CD とは切り離し、その機能はテストを手動で実行、または通常のフローとは別の箇所で実行、と切り離した方がいいんじゃないかと思います。
英語版も書いてみました。
https://dev.to/kakisoft/laravel-test-code-execution-results-depend-on-how-you-handle-the-cache-303