PHPUnitを使用してPHPヘッダーをテストする


97

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内の何かでしょうか?

問題は何でしょうか?


14
これに興味を持っている人が他にいるなら、これをカバーしたかっただけです。PHPUnit(PHP CLIを使用)の実行中はheaders_list()は機能しませんが、代わりにxdebug_get_headers()が機能します。
titel 2012年

回答:


123

問題は、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

これをブートストラップファイルに追加して修正してください。

<?php
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
    define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php');
}

7
すでに定義された定数のxyz:注意:いくつかの定義()文PHPUnit_Framework_Exceptionがあり、この原因のエラー
Minhaz

1
@mebjasそれは無関係に聞こえます。
SamHennessy 14

4
適用するとこれが得られました:PHP Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SplFileInfo' is not allowed' in phar:///usr/local/bin/phpunit/phpunit/Util/GlobalState.php:211
t1gor

2
これは間違いなく問題を解決するための最良のオプションです。それは魅力のように働きました!
xarlymg89

2
セットヘッダーの配列を取得するには、xdebug_get_headers()を使用する必要がありました。headers_list()グローバル関数が私の場合機能しませんでした。
Shalom Sam

107

別のプロセスでテストを実行しても問題は解決しますが、大規模なテストスイートを実行すると、顕著なオーバーヘッドが発生します。

私の修正は、phpunitの出力をstderrに送ることでした。

phpunit --stderr <options>

これで問題が解決するはずです。また、ラッパー関数を作成してコード内のすべての出現箇所を置き換える必要がないことも意味します。


3
鮮やかさ!コードに変更を加えたり、個別のプロセスを実行したりする必要はありません。
alexfernandez 2012年

しかし、私はまだエラーを表示し、error_reporting(E_ALL)の出力を取得しますか?
spankmaster79 2013

1
@ spankmaster79はい、ターミナルの標準エラーに移動します。デフォルトでは、ほとんどの端末は標準出力と標準エラーを一緒に出力しますが、実際には別々のストリームです。
ジョンケアンズ

私は作られていました!!! このトリックのtnx、それは理にかなっています、エラーはstderrorに報告されるべきです!!! Tnx
th3n3rd

42
stderr="true"phpunit.xmlに追加して、いくつかのキーストロークを保存できます。
tszming 2014

9

余談ですが、私headers_list()は0要素を返し続けました。私は質問に対する@titelのコメントに気づき、ここで特に言及する価値があると考えました:

これに興味を持っている人が他にいるのなら、これを取り上げたかっただけです。headers_list()PHPunit(PHP CLIを使用)の実行中は機能しませんが、xdebug_get_headers()代わりに機能します。

HTH


4

コメントですでに述べたように、XML構成ファイルでprocessIsolationを定義する方が良い解決策だと思います

     <?xml version="1.0" encoding="UTF-8"?>
     <phpunit
        processIsolation            = "true"
        // ... 
     >
     </phpunit>

このように、同僚を苛立たせる--stderrオプションを渡す必要はありません。


4
おそらく、それを必要とするテストのためだけに定義する方が良いでしょう。すべてのテストに設定すると、テストの実行が遅くなります。
Shi

3

テスト済み/インクルードされたファイル$_SESSION内で使用するために、より根本的な解決策がありました。../PHPUnit/Utils/Printer.phpにあるPHPUnitファイルの1つを編集して、「print $ buffer」コマンドの前に"session_start();"

それは魅力のように私のために働いた。しかし、私は「冗談」ユーザーの解決策が今までのところすべての中で最高だと思います。


リポジトリでプルリクエストを送信しましたか?これはよくある問題だと思います。
t1gor

ヒントをありがとう、phpunit bootstrap.phpでsession_start()を呼び出しました。これは私にとっては
うまくいき

0

@runInSeparateProcessの代替ソリューションは、PHPUnitの実行時に--process-isolationオプションを指定することです。

name@host [~/test]# phpunit --process-isolation HeadersTest.php

これは、phpunit.xmlでprocessIsolation = "true"オプションを設定するのと似ています。

このソリューションには--stderrオプションを指定するのと同じような利点/欠点がありますが、私の場合は機能しませんでした。基本的に、コードを変更する必要はありませんが、各テストを個別のPHPプロセスで実行することによりパフォーマンスが低下する可能性があります。


これは、原因を追跡していくつかのテストを実行する最初のステップとなる場合がありますが、保守可能なテストを作成するには、注釈をテストファイルに直接埋め込むだけです。コマンドラインから必要な「特別な」オプションが少ないほど、CIシステム構成のメンテナンスが容易になります。
Shi

誰が#failに格下げしたか。この答えは別の選択肢として正しいです。
fb

0

テスト後にPHPUnitからヘッダーを取得するには、-stderrパラメーターを使用します。

phpunit --stderr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.