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?
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');
}
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.
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 funktioniertxdebug_get_headers()
.
HTH
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.
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.
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.