🌿

PHPUnitのテストクラスのメソッドの動く順番を調べた(PHPUnit 13対応)

に公開

はじめに

以前書いた記事がPHPUnit 10対応した内容だったので今回はPHPUnit 13に対応した形で書き直しました。

https://zenn.dev/naopusyu/articles/42d393c1c1b4bc

環境

  • PHP 8.5.3
  • PHPUnit 13.0.5

調べる対象と確認用コード

違いを出す必要もないので以前と同じメソッドを対象にします。

  • setUp
  • tearDown
  • setUpBeforeClass
  • tearDownAfterClass
  • assertPreConditions
  • assertPostConditions
  • onNotSuccessfulTest
  • DataProvider

また、確認用コードも一緒です。(PHPUnit 10 → 13で変更する箇所はなかったです。)

載せておきますが一緒なので閉じています。
<?php

declare(strict_types=1);

namespace Tests;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Throwable;

class LifecycleTest extends TestCase
{
    public static function setUpBeforeClass(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
    }

    public static function tearDownAfterClass(): void
    {
        fwrite(STDOUT, PHP_EOL . __METHOD__ . PHP_EOL);
    }

    protected function setUp(): void
    {
        fwrite(STDOUT, PHP_EOL . __METHOD__ . PHP_EOL);
    }

    protected function tearDown(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
    }

    protected function assertPreConditions(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
    }

    protected function assertPostConditions(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
    }

    protected function onNotSuccessfulTest(Throwable $t): never
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
        throw $t;
    }

    public static function dataProvider(): array
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
        return [
            [1],
            [2],
            [3],
        ];
    }

    public function testMethod1(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
        $this->assertTrue(true);
    }

    public function testMethod2(): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
        $this->assertTrue(false);
    }

    #[DataProvider('dataProvider')]
    public function testMethod3(int $a): void
    {
        fwrite(STDOUT, __METHOD__ . PHP_EOL);
        $this->assertTrue(true);
    }
}

結果

結果も以前と同じでした。

載せておきますが一緒なので閉じています。
% ./vendor/bin/phpunit tests/LifecycleTest.php
Tests\LifecycleTest::dataProvider
PHPUnit 13.0.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.5.3

Tests\LifecycleTest::setUpBeforeClass

Tests\LifecycleTest::setUp
Tests\LifecycleTest::assertPreConditions
Tests\LifecycleTest::testMethod1
Tests\LifecycleTest::assertPostConditions
Tests\LifecycleTest::tearDown
.
Tests\LifecycleTest::setUp
Tests\LifecycleTest::assertPreConditions
Tests\LifecycleTest::testMethod2
Tests\LifecycleTest::tearDown
Tests\LifecycleTest::onNotSuccessfulTest
F
Tests\LifecycleTest::setUp
Tests\LifecycleTest::assertPreConditions
Tests\LifecycleTest::testMethod3
Tests\LifecycleTest::assertPostConditions
Tests\LifecycleTest::tearDown
.
Tests\LifecycleTest::setUp
Tests\LifecycleTest::assertPreConditions
Tests\LifecycleTest::testMethod3
Tests\LifecycleTest::assertPostConditions
Tests\LifecycleTest::tearDown
.
Tests\LifecycleTest::setUp
Tests\LifecycleTest::assertPreConditions
Tests\LifecycleTest::testMethod3
Tests\LifecycleTest::assertPostConditions
Tests\LifecycleTest::tearDown
.                                                               5 / 5 (100%)
Tests\LifecycleTest::tearDownAfterClass


Time: 00:00.003, Memory: 14.00 MB

There was 1 failure:

1) Tests\LifecycleTest::testMethod2
Failed asserting that false is true.

/phpunit-lifecycle/phpunit13/tests/LifecycleTest.php:68

FAILURES!
Tests: 5, Assertions: 5, Failures: 1.    
  1. DataProvider
    • 最初に1回だけ動く
  2. setUpBeforeClass
    • 最初に1回だけ動く
  3. setUp
    • 各テストメソッドの実行前に動く
  4. assertPreConditions
    • 各テストメソッドの実行前に動く
  5. テストメソッド
  6. assertPostConditions
    • 各テストメソッドの実行後に動く(ただし、テストが成功した場合のみ動く)
  7. tearDown
    • 各テストメソッドの実行後に動く
  8. onNotSuccessfulTest
    • 各テストメソッドの実行後に動く(ただし、テストが失敗した場合のみ動く)
  9. tearDownAfterClass
    • 最後に1回だけ動く

イベントシステムを含めた状態で動く順番も調べてみる

以前と同じ結果では書き直す意味も薄れるので今回はイベントシステムを含めた状態で動く順番も調べてみます。
なお、PHPUnitのイベントシステムはPHPUnit 10以降に導入された仕組みです。

https://docs.phpunit.de/en/13.0/events.html

上記のURLに書かれている全てのイベントがどのタイミングで動くのか1つ1つ調べるには多すぎるので今回は実行時のオプションに --log-events-text を付けて調べてみます。

% ./vendor/bin/phpunit tests/LifecycleTest.php --log-events-text lifecycle.log

// 実行結果が表示している

lifecycle.logファイルに出力しているのでそちらを表示して確認します。

ちょっと長いので閉じておきます。
% cat ./lifecycle.log
PHPUnit Started (PHPUnit 13.0.5 using PHP 8.5.3 (cli) on Darwin)
Test Runner Configured
Event Facade Sealed
Data Provider Method Called (Tests\LifecycleTest::dataProvider for test method Tests\LifecycleTest::testMethod3)
Data Provider Method Finished for Tests\LifecycleTest::testMethod3:
- Tests\LifecycleTest::dataProvider
Test Suite Loaded (5 tests)
Test Runner Started
Test Suite Sorted
Test Runner Execution Started (5 tests)
Test Suite Started (Tests\LifecycleTest, 5 tests)
Before First Test Method Called (Tests\LifecycleTest::setUpBeforeClass)
Before First Test Method Finished:
- Tests\LifecycleTest::setUpBeforeClass
Test Preparation Started (Tests\LifecycleTest::testMethod1)
Before Test Method Called (Tests\LifecycleTest::setUp)
Before Test Method Finished:
- Tests\LifecycleTest::setUp
Pre Condition Method Called (Tests\LifecycleTest::assertPreConditions)
Pre Condition Method Finished:
- Tests\LifecycleTest::assertPreConditions
Test Prepared (Tests\LifecycleTest::testMethod1)
Post Condition Method Called (Tests\LifecycleTest::assertPostConditions)
Post Condition Method Finished:
- Tests\LifecycleTest::assertPostConditions
After Test Method Called (Tests\LifecycleTest::tearDown)
After Test Method Finished:
- Tests\LifecycleTest::tearDown
Test Passed (Tests\LifecycleTest::testMethod1)
Test Finished (Tests\LifecycleTest::testMethod1)
Test Preparation Started (Tests\LifecycleTest::testMethod2)
Before Test Method Called (Tests\LifecycleTest::setUp)
Before Test Method Finished:
- Tests\LifecycleTest::setUp
Pre Condition Method Called (Tests\LifecycleTest::assertPreConditions)
Pre Condition Method Finished:
- Tests\LifecycleTest::assertPreConditions
Test Prepared (Tests\LifecycleTest::testMethod2)
Test Failed (Tests\LifecycleTest::testMethod2)
Failed asserting that false is true.
After Test Method Called (Tests\LifecycleTest::tearDown)
After Test Method Finished:
- Tests\LifecycleTest::tearDown
Test Finished (Tests\LifecycleTest::testMethod2)
Test Suite Started (Tests\LifecycleTest::testMethod3, 3 tests)
Test Preparation Started (Tests\LifecycleTest::testMethod3#0)
Before Test Method Called (Tests\LifecycleTest::setUp)
Before Test Method Finished:
- Tests\LifecycleTest::setUp
Pre Condition Method Called (Tests\LifecycleTest::assertPreConditions)
Pre Condition Method Finished:
- Tests\LifecycleTest::assertPreConditions
Test Prepared (Tests\LifecycleTest::testMethod3#0)
Post Condition Method Called (Tests\LifecycleTest::assertPostConditions)
Post Condition Method Finished:
- Tests\LifecycleTest::assertPostConditions
After Test Method Called (Tests\LifecycleTest::tearDown)
After Test Method Finished:
- Tests\LifecycleTest::tearDown
Test Passed (Tests\LifecycleTest::testMethod3#0)
Test Finished (Tests\LifecycleTest::testMethod3#0)
Test Preparation Started (Tests\LifecycleTest::testMethod3#1)
Before Test Method Called (Tests\LifecycleTest::setUp)
Before Test Method Finished:
- Tests\LifecycleTest::setUp
Pre Condition Method Called (Tests\LifecycleTest::assertPreConditions)
Pre Condition Method Finished:
- Tests\LifecycleTest::assertPreConditions
Test Prepared (Tests\LifecycleTest::testMethod3#1)
Post Condition Method Called (Tests\LifecycleTest::assertPostConditions)
Post Condition Method Finished:
- Tests\LifecycleTest::assertPostConditions
After Test Method Called (Tests\LifecycleTest::tearDown)
After Test Method Finished:
- Tests\LifecycleTest::tearDown
Test Passed (Tests\LifecycleTest::testMethod3#1)
Test Finished (Tests\LifecycleTest::testMethod3#1)
Test Preparation Started (Tests\LifecycleTest::testMethod3#2)
Before Test Method Called (Tests\LifecycleTest::setUp)
Before Test Method Finished:
- Tests\LifecycleTest::setUp
Pre Condition Method Called (Tests\LifecycleTest::assertPreConditions)
Pre Condition Method Finished:
- Tests\LifecycleTest::assertPreConditions
Test Prepared (Tests\LifecycleTest::testMethod3#2)
Post Condition Method Called (Tests\LifecycleTest::assertPostConditions)
Post Condition Method Finished:
- Tests\LifecycleTest::assertPostConditions
After Test Method Called (Tests\LifecycleTest::tearDown)
After Test Method Finished:
- Tests\LifecycleTest::tearDown
Test Passed (Tests\LifecycleTest::testMethod3#2)
Test Finished (Tests\LifecycleTest::testMethod3#2)
Test Suite Finished (Tests\LifecycleTest::testMethod3, 3 tests)
After Last Test Method Called (Tests\LifecycleTest::tearDownAfterClass)
After Last Test Method Finished:
- Tests\LifecycleTest::tearDownAfterClass
Test Suite Finished (Tests\LifecycleTest, 5 tests)
Test Runner Execution Finished
Test Runner Finished
PHPUnit Finished (Shell Exit Code: 1)

大雑把に書くとイベントは次のように動くことが確認できました。
※ 括弧内は調べる対象のメソッドが動いたタイミングです。

  1. PHPUnitの開始
  2. 設定(phpunit.xml)の読み込み
  3. イベントシステムの初期化
  4. データプロバイダーの読み込み(DataProvider)
  5. テストの開始
  6. テストの前処理(setUpBeforeClass)
  7. テストメソッドの前処理(setUp,assertPreConditions)
  8. テストメソッドの実行
  9. テストメソッドの結果
  10. テストメソッドの後処理(assertPostConditions,tearDown)
  11. テストの後処理(tearDownAfterClass)
  12. テストの終了

まとめ

PHPUnitのバージョンが上がってもメソッドの動く順番に変化はなかったです。

またイベントシステムを含めた状態で動く順番も調べたことで、
テストメソッドが動くまでの流れがより詳細となりました。

今回確認しなかった他のイベントを含めることでさらに流れが整理できそうなので、
それは別の機会に調べる予定です。

GitHubで編集を提案

Discussion