対象: Symfony 7.4

参考

Testing

インストール

composer require --dev symfony/test-pack

symfony/test-pack は、phpunit/phpunitsymfony/browser-kitsymfony/css-selector をまとめて require-dev に追加するパックです。 インストールされる PHPUnit のバージョンは、パックの制約と PHP のバージョンによって決まります。実際の値は composer.json / composer.lock で確認してください。

[!NOTE] composer.json の次の記述は、symfony/test-pack の導入時ではなく、symfony new(または composer create-project symfony/skeleton)の実行時に設定されます。

"autoload-dev": {
    "psr-4": {
        "App\\Tests\\": "tests/"
    }
}

テストの実行

vendor/bin/phpunit

設定は phpunit.dist.xml(版・レシピによっては phpunit.xml.dist)にあり、テスト実行時は APP_ENV=test が使われます。

テストの種類と親クラス

[!IMPORTANT] 親クラスはおもに以下のクラスを使用します。

  • 単体テスト PHPUnit 提供クラス PHPUnit\Framework\TestCase
    class SampleTest extends \PHPUnit\Framework\TestCase { }
  • 結合テスト Symfony 提供クラス Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
    class SampleTest extends \Symfony\Bundle\FrameworkBundle\Test\KernelTestCase { }
  • アプリケーションテスト(HTTP) Symfony\Bundle\FrameworkBundle\Test\WebTestCase

以下の「サービスのテスト」は、カーネルとサービスコンテナを起動するため、単体テストではなく結合テストです。

サービスのテスト

<?php

namespace App\Service;

class Sample
{
    public function echo(string $message): string
    {
        return $message;
    }
}
<?php

namespace App\Tests\Service;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use App\Service\Sample;

// KernelTestCase を継承
class SampleServiceTest extends KernelTestCase
{
    public function testSomething(): void
    {
        // (1) boot the Symfony kernel
        self::bootKernel();

        // (2) use static::getContainer() to access the service container
        $container = static::getContainer();

        // (3) run some service & test the result
        $sample = $container->get(Sample::class);

        $this->assertEquals('Hello World!', $sample->echo('Hello World!'));
    }
}

private サービスの取得

static::getContainer() は「テスト用コンテナ」を返します。このコンテナから、public サービスと、削除されていない private サービスを取得できます。

サービスは既定で private です。private サービスは、他のサービスから使われていない場合、コンテナのコンパイル時に削除されます。上記の App\Service\Sample は、どこからも使われていなければ削除されるため、$container->get(Sample::class) が失敗します。

この場合に限り、services_test.yaml でテストのときだけ public にします。

# config/services_test.yaml
services:
    App\Service\Sample:
        public: true # テストのときだけ public にする(未使用の private サービスの削除を防ぐ)

config/services.yaml 側に public: false を書く必要はありません(既定が private です)。

[!IMPORTANT] services_test.yaml はテスト環境のときだけ読み込まれ、次のように動作します。

  • services.yaml に定義されたサービスはすべて適用される
  • services_test.yaml に同じサービスがある場合は、それで上書きされる
  • services_test.yaml に新しいサービスを追加できる