wake-up-neo.net

Prüfung PHP Header mit PHPUnit

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

Das Problem ist, dass auf meiner Maschine Folgendes:

<?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 sogar das:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

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

        ob_clean();
    }
}

diesen Fehler zurückgeben:

[email protected] [~/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 ob vor dem Test etwas anderes an das Terminal ausgegeben wird, obwohl keine andere Datei enthalten ist und kein anderes Zeichen vor dem Anfang des PHP - Tags vorhanden ist. Könnte es etwas in PHPunit sein, das dies verursacht?

Was könnte das Problem sein?

78
titel

Das Problem ist, dass PHPUnit eine Kopfzeile auf den Bildschirm druckt und an diesem Punkt können Sie keine weiteren Kopfzeilen hinzufügen.

Sie umgehen den Test in einem isolierten Prozess. Hier ist ein Beispiel

<?php

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

Dies führt zu:

$ 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, wird der Fehler angezeigt:

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

Fügen Sie dies der Bootstrap-Datei hinzu, um dies zu beheben:

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

Das Ausführen des Tests in einem separaten Prozess behebt zwar das Problem, es ist jedoch ein erheblicher Mehraufwand erkennbar, wenn eine große Testreihe ausgeführt wird.

Meine Lösung bestand darin, die Ausgabe von phpunit wie folgt an stderr zu leiten:

phpunit --stderr <options>

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

96
Jon Cairns

Nebenbei: Für mich hat headers_list() immer 0 Elemente zurückgegeben. Ich bemerkte den Kommentar von @titel zu der Frage und stellte fest, dass er hier besonders erwähnt werden sollte:

Ich wollte nur darüber berichten, wenn es andere Interessenten gibt auch hier. headers_list() funktioniert nicht, während PHPunit ausgeführt wird (was PHP CLI verwendet), aber stattdessen funktioniert xdebug_get_headers().

HTH

8
Melle

Ich hatte eine radikalere Lösung, um $_SESSION in meinen getesteten/enthaltenen -Dateien zu verwenden . Ich bearbeitete eine der PHPUnit -Dateien unter ../PHPUnit/Utils/Printer.php, um eine "session_start();" vor dem -Befehl "print $ buffer" zu haben. 

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

3
Sergio Abreu

Wie schon in einem Kommentar erwähnt, ist es meiner Meinung nach eine bessere Lösung, ProcessIsolation in der XML-Konfigurationsdatei zu definieren 

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

Auf diese Weise müssen Sie die Option --stderr nicht bestehen, was Ihre Kollegen irritieren könnte. 

0
PepeNietnagel

Eine Alternative zu @runInSeparateProcess ist die Angabe der Option --process-isolation beim Ausführen von PHPUnit:

[email protected] [~/test]# phpunit --process-isolation HeadersTest.php

Das ist analog zum Setzen 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 erforderlich, auch wenn die Ausführung jedes Tests in einem separaten PHP -Prozess zu einem Performance-Hit führen kann.

0
AlexB