header() 関数はその実行前に何らかの標準出力がされていると「Cannot modify header information
」というエラーを吐いてしまいます。
PHPUnit はテスト中のメッセージを標準出力に逐一吐き出すため、そのままでは header() 関数を用いたメソッドのテストができません。
現象
たとえば下記のようなテストケースはエラーで止まります。
class Api {
public function output($data, $response_code = 200) {
http_response_code($response_code);
header('Content-Type: application/json'); // この行の前に PHPUnit が標準出力にテスト進捗を逐次出力するせいで、エラーになる
$output = json_encode($data);
echo $output;
return $output;
}
}
class ApiTest extends \PHPUnit_Framework_TestCase {
/*
* @covers Api::output
*/
public function testOutput() {
$data = ['foo' => 'bar'];
$response_code = 200;
ob_start();
$actual = $this->Api->output($data, $response_code);
$output = ob_get_contents();
$expected = json_encode($data);
$this->assertEquals($expected, $actual);
$this->assertEquals($output, $actual);
$this->assertEquals(http_response_code(), $response_code);
ob_clean();
}
}
上のテストを実行すると、以下のようなエラーを吐きます。
Cannot modify header information - headers already sent by (output started at C:\xampp\php\pear\PHPUnit\Util\Printer.php:172)
対策
PHPUnit の @runInSeparateProcess
アノテーションを利用することで、テストケースだけを別プロセスで実行することができます。
つまり、header() 関数を使うテストだけは標準出力が真っさらなプロセスでテストできるので、エラーを吐きません。
/**
* @covers Api::output
* @runInSeparateProcess
*/
public function testOutput() {
// ...
}
PHPUnit 3.7.8 by Sebastian Bergmann.
.
Time: 3 seconds, Memory: 2.75Mb
OK (1 test, 3 assertions)
header() 関数を使ったメソッドのテストをする際には覚えておきたいテクニックです。