以下のような Laravel のテストコードがあります(本来はもっと複雑な問題だったのを絞り込んで、短い単純なテストコードで問題が再現できるようにしました。)
vagrant@server1:~/vanilla$ $ ./artisan --version
Laravel Framework 9.21.5
vagrant@server1:~/vanilla$ cat tests/Feature/LogTest.php
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Support\Facades\Log;
class LogTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
Log::debug('Start ' . __CLASS__);
}
public function test_example()
{
$this->assertEquals(100+100, 200);
}
}
このテストコードを、作りたての Laravel Project(vanilla) で動かすと、正しく動作します。
vagrant@server1:~/vanilla$ ./vendor/bin/phpunit tests/Feature/LogTest.php
PHPUnit 10.1.3 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.19
Configuration: /home/vagrant/vanilla/phpunit.xml
. 1 / 1 (100%)
Time: 00:00.128, Memory: 10.00 MB
OK (1 test, 1 assertion)
ところが、これを既存のプロジェクト(problematic)に入れると、なぜか動きません。
vagrant@server1:~/problematic$ ./vendor/bin/phpunit tests/Feature/LogTest.php
PHPUnit 9.5.21 #StandWithUkraine
E 1 / 1 (100%)
Time: 00:00.033, Memory: 6.00 MB
There was 1 error:
1) Tests\Feature\LogTest::test_example
RuntimeException: A facade root has not been set.
/opt/problematic/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:334
/opt/problematic/tests/Feature/LogTest.php:13
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
デバッガで追ってみると、vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php::resolveFacadeInstance()で null が返って来ています。$app が初期化されていないようです。
原因は、親クラスの tests/TestCase.php に、共通処理を後から入れられるよう安易に setUp() を書いていたのですが、その中で parent::setUp(); を呼んでいなかったためでした。これを追加することで、うまく機能するようになりました。
vagrant@server1:~/problematic$ cat tests/TestCase.php
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
public function setUp(): void
{
parent::setUp(); // これが抜けていた
}
}
フレームワークは便利だけど、習熟には時間がかかりますね。。。単に年のせいか?