この記事は当初Qiitaに掲載していたものです。移設しました。


phpunit では標準出力のテスト方法として expectOutputString() が用意されていますが、これは echo など出力バッファ経由で出力されるものをテストするもので、ob_start() ob_get_contents() のセットで出力を取得できるものしか取り扱えません。

一方、CLIツールを作成する場合はリアルタイム表示するためにバッファリングを回避する方法として STDOUTfwrite() する方法が使われることがあります。これをすると ob_get_contents() で拾えなくなるため、 expectOutputString() ではテストできなくなります。

STDOUT はストリームなので、ストリームフィルタで出力内容を取得することができます。

<?php

class CLITestStreamFilter extends \php_user_filter
{
    public static $buffer = '';

    public function filter($in, $out, &$consumed, $closing)
    {
        while ($bucket = stream_bucket_make_writeable($in)) {
            self::$buffer .= $bucket->data;
            $consumed += $bucket->datalen;
        }
        return PSFS_PASS_ON;
    }
}

stream_filter_register('CLITestStreamFilter', 'CLITestStreamFilter');


class CLITest extends PHPUnit\Framework\TestCase
{
    private $stream_filter;

    public function setUp()
    {
        CLITestStreamFilter::$buffer = '';
        $this->stream_filter = stream_filter_append(STDOUT, 'CLITestStreamFilter');
    }

    public function tearDown()
    {
        stream_filter_remove($this->stream_filter);
    }

    public function testStdout()
    {
        fwrite(STDOUT, "first.\n");
        fwrite(STDOUT, "second.\n");
        fwrite(STDOUT, "third.\n");

        $expected = <<<EOT
first.
second.
third.

EOT;
        $this->assertEquals($expected, CLITestStreamFilter::$buffer);
    }
}