Frage

Im Moment arbeite ich mit PHPUnit zu versuchen und zu entwickeln Tests neben was ich schreibe, aber ich bin zur Zeit auf die Arbeit der Session Manager zu schreiben und Fragen habe dabei ...

Der Konstruktor für die Session Handling Klasse

private function __construct()
{
    if (!headers_sent())
    {
        session_start();
        self::$session_id = session_id();
    }
}

Wie jedoch PHPUnit Text sendet, bevor er die Prüfung beginnt, kehrt jede Prüfung auf diesem Objekt einen Test nicht bestanden, da die HTTP „Headers“ gesendet wurden ...

War es hilfreich?

Lösung

Nun, Ihr Session-Manager wird im Wesentlichen durch Design gebrochen. Um die Lage sein, etwas zu testen, muss es möglich sein, sie zu isolieren, von Nebenwirkungen. Leider ist PHP so konzipiert, dass es großzügigen Einsatz von globalem Zustand (echo, header, exit, session_start usw. usw.).

ermutigt

Das Beste, was Sie tun können, ist die Nebenwirkungen in einer Komponente zu isolieren, die zur Laufzeit ausgetauscht werden können. Auf diese Weise können Sie Ihre Tests verspott Objekte verwenden, während der Live-Code verwendet Adapter, die echte Nebenwirkungen haben. Sie werden feststellen, dass dies nicht gut mit Singletons spielt, die ich nehme an, Sie verwenden. So haben Sie einen anderen Mechanismus für das Erhalten gemeinsam genutzte Objekte verteilt, um Ihren Code zu verwenden. Sie können mit einer statischen Registrierung beginnen, aber es gibt noch bessere Lösungen, wenn Sie nicht ein bisschen Lernen ausmachen.

Wenn Sie das nicht tun können, haben Sie immer die Möglichkeit, Integrationstests zu schreiben. Z.B. Verwendung der äquivalenten die PHPUnit von WebTestCase .

Andere Tipps

Erstellen

eine Bootstrap-Datei für phpunit, welche Anrufe:

session_start();

Dann starten phpunit wie folgt aus:

phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/

Die Bootstrap-Datei, bevor alles andere aufgerufen wird, so hat der Header nicht gesendet und alles sollte gut funktionieren.

PHPUnit druckt Ausgabe wie die Tests so läuft verursacht headers_sent () true zurück, auch in Ihrem ersten Test.

Um dieses Problem für eine ganze Testsuite überwinden müssen Sie einfach () in der Setup-Skript verwenden ob_start.

Zum Beispiel, sagen, Sie haben eine Datei AllTests.php benannt, die das erste, was von PHPUnit geladen. Das Skript könnte wie folgt aussehen:

<?php

ob_start();

require_once 'YourFramework/AllTests.php';

class AllTests {
    public static function suite() {
        $suite = new PHPUnit_Framework_TestSuite('YourFramework');
        $suite->addTest(YourFramework_AllTests::suite());
        return $suite;
    }
}

Ich hatte das gleiche Problem, und ich löste es durch phpunit mit --stderr Flagge Aufruf wie folgt aus:

phpunit --stderr /path/to/your/test

Hoffe, es hilft jemand!

Ich denke, die „richtige“ Lösung, die eine sehr einfache Klasse zu erstellen ist (so einfach nicht getestet werden muss), das ist ein Wrapper für Funktionen von PHP-Session bezogen, und es verwendet, anstatt session_start() des Aufrufs usw. direkt .

Im Test bestehen Mock-Objekt anstelle eines echten Stateful, untestable Session-Klasse.

private function __construct(SessionWrapper $wrapper)
{
   if (!$wrapper->headers_sent())
   {
      $wrapper->session_start();
      $this->session_id = $wrapper->session_id();
   }
}

Ich frage mich, warum niemand hat aufgelistet XDebug Option:

/**
 * @runInSeparateProcess
 * @requires extension xdebug
 */
public function testGivenHeaderIsIncludedIntoResponse()
{
    $customHeaderName = 'foo';
    $customHeaderValue = 'bar';

    // Here execute the code which is supposed to set headers
    // ...

    $expectedHeader = $customHeaderName . ': ' . $customHeaderValue;
    $headers = xdebug_get_headers();

    $this->assertContains($expectedHeader, $headers);
}

Können Sie die Ausgabe-Pufferung nicht verwenden, bevor Sie den Test starten? Wenn Sie alles Puffer, der ausgegeben wird, sollten Sie keine Probleme haben Einstellung alle Header wie keine Ausgabe noch an diesem Punkt an den Client gesendet worden wäre.

Auch wenn OB irgendwo in Ihrem Klassen verwendet wird, ist es stapelbar und OB sollte nicht beeinflussen, was im Inneren vor sich geht.

Soweit ich weiß, Zend Framework verwendet die gleiche Ausgabepufferung für ihre Zend_Session Paket-Tests. Sie können einen Blick auf ihre Testfälle nehmen Sie, um loszulegen.

Die Erzeugung der Bootstrap-Datei, wies darauf hin, 4 Beiträge scheint wieder die sauberste Weg, um dieses.

Oft mit PHP sind wir zu halten und versuchen, irgendeine Art von Engineering-Disziplin zu Legacy-Projekten hinzuzufügen, die bodenlos zusammengesetzt werden. Wir haben nicht die Zeit (oder die Behörde), um den ganzen Haufen von Müll, zu Graben und starten wieder, so dass die erste anwer von troelskn ist nicht immer möglich, als einen Weg nach vorn. (Wenn wir den ursprünglichen Entwurf zurückgehen könnten, dann könnten wir PHP zusammen Graben und verwenden etwas moderneren, wie Rubin oder Python, anstatt zu helfen, diese COBOL der Welt Web-Entwicklung zu verewigen.)

Wenn Sie versuchen, Unit-Tests für Module zu schreiben, die session_start oder setcookie ganzen sie verwenden, als Beginn der Sitzung in einer Bootstrap-Datei wird Ihre runden diese Fragen.

Als ich meine Unittesting Bootstrap jetzt (ja ich weiß, die meisten von Ihnen tun das nicht), ich laufe in das gleiche Problem (beide header () und session_start ()). Die Lösung, die ich gefunden ist ziemlich einfach, in Ihrem Unittest Bootstrap eine Konstante definieren und einfach zu überprüfen, bevor Sie die Kopf- oder Starten der Sitzung zu senden:

// phpunit_bootstrap.php
define('UNITTEST_RUNNING', true);

// bootstrap.php (application bootstrap)
defined('UNITTEST_RUNNING') || define('UNITTEST_RUNNING', false);
.....
if(UNITTEST_RUNNING===false){
    session_start();
}

Ich bin damit einverstanden, dass dies durch Design ist nicht perfekt, aber ich bin Unittesting eine bestehende Anwendung, große Teile Umschreiben nicht erwünscht ist. Ich habe auch die gleiche Logik mit dem __call privaten Methoden zu testen, mit () und __set () magischen Methoden.

public function __set($name, $value){
    if(UNITTEST_RUNNING===true){
       $name='_' . $name;
       $this->$name=$value;
    }
    throw new Exception('__set() can only be used when unittesting!');
 }

Es scheint, dass Sie benötigen, um die Sitzung zu injizieren, so dass Sie Ihren Code testen können. Die beste Option, die ich verwendet habe ist Aura.Auth für den Authentifizierungsprozess und mit Null Session und NullSegment zum Testen.

Aura Test mit null-Sitzungen

Die Aura Rahmen geschrieben ist wunderschön und man kann Aura.Auth ohne andere Aura Rahmen Abhängigkeiten auf eigene verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top