Frage Testen Sie PHP-Header mit PHPUnit


Ich versuche, PHPunit zu verwenden, um eine Klasse zu testen, die einige benutzerdefinierte Header ausgibt.

Das Problem ist das auf meiner Maschine:

<?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);
    }
}

oder auch das:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        header_remove();

        ob_clean();
    }
}

Gib diesen Fehler zurück:

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.

Es sieht so aus, als würde vor dem Test noch etwas an das Terminal ausgegeben, obwohl keine andere Datei enthalten ist und vor dem Beginn des PHP-Tags kein anderes Zeichen vorhanden ist. Könnte es etwas in PHPunit sein, das dies verursacht?

Was könnte das Problem sein?


75
2018-03-16 22:04


Ursprung


Antworten:


Das Problem besteht darin, dass PHPUnit eine Kopfzeile auf dem Bildschirm ausgibt. Zu diesem Zeitpunkt können Sie keine Kopfzeilen mehr hinzufügen.

Die Arbeit besteht darin, den Test in einem isolierten Prozess durchzuführen. Hier ist ein Beispiel

<?php

class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testBar()
    {
        header('Location : http://foo.com');
    }
}

Dies wird zu folgenden Ergebnissen führen:

$ phpunit FooTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 1 second, Memory: 9.00Mb

OK (1 test, 0 assertions)

Der Schlüssel ist die Annotation @runInSeparateProcess.

Wenn Sie PHPUnit ~ 4.1 oder etwas verwenden und den Fehler erhalten:

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

Versuchen Sie dies zu Ihrer Bootstrap-Datei hinzuzufügen, um es zu beheben:

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

103
2018-03-17 00:36



Obwohl das Ausführen des Tests in einem separaten Prozess das Problem behebt, ist bei der Ausführung einer umfangreichen Testsuite ein erheblicher Aufwand zu verzeichnen.

Mein Problem war, die Ausgabe von phpunit an stderr zu richten:

phpunit --stderr <options>

Das sollte das Problem beheben und bedeutet auch, dass Sie keine Wrapperfunktion erstellen müssen und alle Vorkommen in Ihrem Code ersetzen müssen.


92
2018-05-30 12:03



Nebenbei: Für mich headers_list() hat immer 0 Elemente zurückgegeben. Ich bemerkte @titelKommentar zu der Frage und dachte, es verdient besondere Erwähnung hier:

Ich wollte das nur abdecken, wenn andere Leute interessiert sind   Auch darin. headers_list() funktioniert nicht, während PHPunit läuft   (die PHP CLI verwendet), aber xdebug_get_headers() funktioniert stattdessen.

HTH


7
2017-10-06 09:29



Ich hatte eine radikalere Lösung, um zu verwenden $_SESSION in meinem getestet / enthalten Dateien. Ich habe eines der PHPUnit Dateien bei ../PHPUnit/Utils/Printer.php Ein ... Haben "session_start();" Vor dem Befehl "print $ buffer".

Es hat für mich wie ein Zauber funktioniert. Aber ich denke, die "joonty" -Benutzerlösung ist die beste von allen bisher.


3
2017-11-09 13:12



Eine alternative Lösung zu @runInSeparateProcess ist die Angabe der Option --process-isolation beim Ausführen von PHPUnit:

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

Das ist analog zur Einstellung der Option processIsolation = "true" in phpunit.xml.

Diese Lösung hat ähnliche Vorteile / Nachteile wie die Angabe der Option --stderr, die jedoch in meinem Fall nicht funktioniert hat. Grundsätzlich sind keine Code-Änderungen notwendig, obwohl es einen Leistungseinbruch geben kann, da jeder Test in einem separaten PHP-Prozess ausgeführt wird.


0
2018-01-23 17:02



Wie bereits in einem Kommentar erwähnt, ist es eine bessere Lösung, processIsolation in der XML-Konfigurationsdatei zu definieren

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

So müssen Sie nicht die Option --stderr bestehen, die Ihre Mitarbeiter irritieren könnte.


0
2018-06-12 20:30