PHPunitを使用して、いくつかのカスタムヘッダーを出力するクラスをテストしようとしています。
問題は、私のマシンでは次のことです:
<?php
class HeadersTest extends PHPUnit_Framework_TestCase {
public function testHeaders()
{
ob_start();
header('Location: foo');
$headers_list = headers_list();
header_remove();
ob_clean();
$this->assertContains('Location: foo', $headers_list);
}
}
またはこれさえ:
<?php
class HeadersTest extends PHPUnit_Framework_TestCase {
public function testHeaders()
{
ob_start();
header('Location: foo');
header_remove();
ob_clean();
}
}
このエラーを返します:
name@Host [~/test]# phpunit --verbose HeadersTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.
E
Time: 0 seconds, Memory: 2.25Mb
There was 1 error:
1) HeadersTest::testHeaders
Cannot modify header information - headers already sent by (output started at /usr/local/lib/php/PHPUnit/Util/Printer.php:173)
/test/HeadersTest.php:9
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
これは、他のファイルが含まれておらず、PHPタグの先頭の前に他の文字がない場合でも、テストの実行前に端末に出力する何かがあるように見えます。これを引き起こしているPHPunit内の何か?
問題は何ですか?
問題は、PHPUnitがヘッダーを画面に出力することであり、その時点でヘッダーを追加することはできません。
回避策は、隔離されたプロセスでテストを実行することです。ここに例があります
<?php
class FooTest extends PHPUnit_Framework_TestCase
{
/**
* @runInSeparateProcess
*/
public function testBar()
{
header('Location : http://foo.com');
}
}
これにより、次の結果が得られます。
$ phpunit FooTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.
.
Time: 1 second, Memory: 9.00Mb
OK (1 test, 0 assertions)
キーは@runInSeparateProcessアノテーションです。
PHPUnit〜4.1などを使用しているときにエラーが発生する場合:
PHP Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in -:378
Stack trace:
#0 {main}
thrown in - on line 378
Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378
Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378
Call Stack:
0.0013 582512 1. {main}() -:0
これをbootstrapファイルに追加して修正してください:
<?php
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php');
}
テストを別のプロセスで実行することで問題は解決しますが、大規模なテストスイートを実行すると顕著なオーバーヘッドが発生します。
私の修正は、phpunitの出力を次のようにstderrに送ることでした:
phpunit --stderr <options>
これで問題は解決するはずです。また、ラッパー関数を作成してコード内のすべての出現箇所を置き換える必要もありません。
余談ですが、私にとってはheaders_list()
は0個の要素を返し続けました。 @ titel の質問に対するコメントに気づき、ここで特に言及する価値があると考えました。
他にも興味がある人がいるなら、これをカバーしたかっただけです。
headers_list()
はPHPunit(PHP CLI)を使用)の実行中は機能しませんが、xdebug_get_headers()
は代わりに機能します。
HTH
tested/includedファイル内で_$_SESSION
_を使用するために、より根本的な解決策がありました。 PHPUnit../ PHPUnit/Utils/Printer.phpのファイルの1つを編集して、command "の前に"session_start();"
を追加しましたprint $ buffer "。
それは私にとって魅力的でした。しかし、私はこれまでのところ、「不愉快な」ユーザーのソリューションが何よりも優れていると思います。
コメントですでに述べたように、XML構成ファイルでprocessIsolationを次のように定義する方が良い解決策だと思います
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
processIsolation = "true"
// ...
>
</phpunit>
このように、同僚を苛立たせる可能性がある--stderrオプションを渡す必要はありません。
@runInSeparateProcessの代替ソリューションは、PHPUnitの実行時に--process-isolationオプションを指定することです。
name@Host [~/test]# phpunit --process-isolation HeadersTest.php
これは、phpunit.xmlでprocessIsolation = "true"オプションを設定することに似ています。
このソリューションには--stderrオプションを指定するのと同様の利点/欠点がありますが、私の場合はうまくいきませんでした。各テストを個別のPHPプロセスで実行するためにパフォーマンスが低下する可能性がありますが、基本的にコードを変更する必要はありません。