PHPUnit のメモ(設定で特定のファイルを対象除外、 Cannot modify header information – headers already sent by … のエラーの回避)

PHPUnit を使っていて少し躓いた部分のメモ。なお、 PHPUnit のバージョンは 9.5.0 で試しました。

設定で特定のファイルを対象除外

設定の値を返すだけの簡単な設定ファイルを作ってあり、それをテストから除外したい場合。

<phpunit
    bootstrap="./tests/bootstrap.php"
    addUncoveredFilesFromWhitelist="true"
    processUncoveredFilesFromWhitelist="true"
    stopOnFailure="false"
    colors="auto">
    <testsuites>
        <testsuite>
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
    <filter>
      <whitelist processUncoveredFilesFromWhitelist="true">
        <directory suffix=".php">./src</directory>
        <exclude>
          <directory suffix=".php">./tests</directory>
          <directory>./template</directory>
        </exclude>
      </whitelist>
    </filter>
</phpunit>

ディレクトリの除外ならば phpunit.xml.dist で上記の whitelist > exclude > directory で囲んだパスを除外できることは知っていました。

<?php

return [
    'base'        => '/',
    'appname'    => 'Config Sample',
];

今回のケースでは、例えばこんな src/config.php があったとします。また、 src/ ディレクトリには他のコードもあるため、 src/ 自体はテスト対象に含めたいとします。

<phpunit
    bootstrap="./tests/bootstrap.php"
    addUncoveredFilesFromWhitelist="true"
    processUncoveredFilesFromWhitelist="true"
    stopOnFailure="false"
    colors="auto">
    <testsuites>
        <testsuite>
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
    <filter>
      <whitelist processUncoveredFilesFromWhitelist="true">
        <directory suffix=".php">./src</directory>
        <exclude>
          <directory suffix=".php">./tests</directory>
          <directory>./template</directory>
          <file>./src/config.php</file>
        </exclude>
      </whitelist>
    </filter>
</phpunit>

whitelist > exclude > file にすれば良し。

Cannot modify header information – headers already sent by … のエラーの回避

とあるメソッドの中に header() 関数が記述されていると、テストの際に

Cannot modify header information – headers already sent by (output started at PATH/TO/PROJECT/vendor/phpunit/phpunit/src/Util/Printer.php:104)

のようなエラーが出てしまいました。

これは PHPUnit はテスト中のメッセージを標準出力に吐き出すので、 header() の前に既に出力がされてしまっている状態になるため引っかかってしまうようです。

対策としては、 PHPUnit の @runInSeparateProcess アノテーションを使用することで、そのテストケースを別プロセスとして動作させること。

これにより header() 前に出力がない状態としてテストするため、引っかからなくなります。

<?php

class DullahanTest extends \PHPUnit\Framework\TestCase
{
    /**
     * @test
     * @runInSeparateProcess
     */
    public function testDullahan()
    {
        // some test code
    }
}

こんなイメージです。

参考

設定で特定のファイルを対象除外

Cannot modify header information – headers already sent by … のエラーの回避

余談

今回ほんの些細なプログラムを書いたのですが、あまりにも些細なものだったので「どうせなら PHPUnit の練習にしよう」と思って取り組みました。結果、 PHPUnit で今まであまり触ってこなかったケースに当たったので、良い勉強になったのかな、と思います。

サンプルプログラムを書く際に参考にしたサイト ( PHPUnit とは関係なし)

password_hash

call_user_func_array

変数の渡し方が若干疑問。

call_user_func_array + FastRoute

str_pad

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。