Phpunit: Serialisierung von 'Closure' ist nicht erlaubt

Erstellt am 2. Jan. 2012  ·  12Kommentare  ·  Quelle: sebastianbergmann/phpunit

Obwohl $GLOBAL Closures seit 01aa34783c9b19d39e568641f3f2dd0fc983b11a & #352 nicht mehr serialisiert werden, verursacht ein $GLOBAL Array, das einen Closure als Wert enthält, immer noch den Fehler "Serialization of 'Closure' is not allowed".

$GLOBALS[] = array( 'foo' => function() { return 'bar'; }  );
typbug

Hilfreichster Kommentar

Ich erhalte dieselbe Fehlermeldung, wenn ich ein new MyRestClient() instanziiere, dessen Konstruktor $this->client = new \GuzzleHttp\Client(); . Es ist auch dasselbe, als ich versucht habe, im Konstruktor meiner Klasse $x=function(){}; . Ich denke, der Guzzle-Client macht intern etwas Ähnliches. Dies macht es unmöglich, jemals innerhalb eines phpunit-Tests zu instanziieren. jetzt bin ich so traurig :schluchz:

Alle 12 Kommentare

Ein weiterer Fall, den ich bekomme

 /* test.php */
 Klasse ClosureTest erweitert PHPUnit_Framework_TestCase
 {
 Funktion testClosure() {
 $this->assertEquals(1, 1);
 call_user_func(Funktion($a) {
 throw new \Exception("test");
 }, 10);
 $this->assertEquals(2, 2);
 }
 }

und dann in Prozessisolation ausführen

 phpunit --process-isolation test.php

du würdest bekommen

 Es gab 1 Fehler:
 1) phTest::testClosure
 PHPUnit_Framework_Exception: Fataler PHP-Fehler: Nicht abgefangene Ausnahme 'Exception' mit Meldung 'Serialization of 'Closure' is not allowed' in -:37
 Stapelverfolgung:
 #0 -(37): serialisieren (Array)
 #1 -(123): __phpunit_run_isolated_test()
 #2 {Haupt}
 eingeworfen - in Zeile 37
 AUSFÄLLE!
 Tests: 1, Behauptungen: 0, Fehler: 1.

Ich hatte das gleiche Problem bei der Verwendung der Prozessisolation, um es zu umgehen, habe ich __sleep zu meinem Testfall hinzugefügt und die Closures darin bereinigt. Für mich hatte ich einige Mocks in den Eigenschaften des Testfalls gespeichert, also war es wirklich meine eigene Schuld, ich hoffe, das hilft jemandem.

Ich habe auch das gleiche Problem und kann das zuvor erwähnte Problem

Pull-Anfragen sind immer willkommen!

Ich weiß, es ist ein bisschen her, aber ich war eine Weile nicht im Projekt. Nach dem Kommentar von

/* test.php */
class closureTest extends PHPUnit_Framework_TestCase
{
    function testClosure() {
        call_user_func(function($a) {
            throw new \Exception("test");
        });
    }
}

Beachten Sie das Fehlen eines angegebenen Arguments am Ende von call_user_func . Die Serialisierungsausnahme resultiert aus dem Versuch, das PHPUnit_Framework_TestResult-Objekt zu serialisieren. Dieser Serialisierungsversuch ist in Zeile 42 von PHPUnit/Framework/Process/TestCaseMethod.tpl.dist . Der beleidigende Teil des zu serialisierenden Objekts ist eine Closure-Referenz in der Trace-Hierarchie der ausgelösten Exception:

[1] => Array
    (
        [function] => {closure}
        [class] => Issue451Test
        [type] => ->
        [args] => Array
            (
            )

)

Da dies das erste Mal ist, dass ich PHPUnit patche, habe ich die Frage, ob ich die Closure abstreifen oder anderweitig gutartig modifizieren kann - was zweifellos die Verwendung von Reflection beinhalten würde - gibt es eine PHPUnit-Best-Practice-Methode, um damit umzugehen? ? Irgendwelche Gedanken oder Inputs zumindest?

Außerdem habe ich einen Test unter Regressions/GitHub geschrieben. Ist das akzeptabel?

@kunjalpopat , in Bezug auf Ihr Problem, das erste, was ich überprüfen würde, sind Ausnahmen. Bei der Prozessisolation können ausgelöste Ausnahmen die Meldung "Serialization of Closure" anzeigen. Versuchen Sie, Ihren Testcode in ein try/catch zu packen und sehen Sie, ob das das Problem behebt. Wenn dies der Fall ist, sollten Sie die Abdeckung von try/catch reduzieren, bis Sie den Problembereich gefunden haben.

Das Problem liegt in PHPUnit_Util_GlobalState::backupGlobals :

if ($key != 'GLOBALS' &&
    !in_array($key, $superGlobalArrays) &&
    !in_array($key, $blacklist) &&
    !$GLOBALS[$key] instanceof Closure) {  // <-- this is the problem
    self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]);
}

Ich habe mir einen Helfer in PHPUnit_Util_GlobalState :

public static function checkIfThereIsClosureInIt($arr) {
    if ($arr instanceof Closure)
        return true;
    if (is_object($arr))
        $arr = get_object_vars($arr);
    if (is_array($arr))
        foreach ($arr as $x)
            if (PHPUnit_Util_GlobalState::checkIfThereIsClosureInIt($x))
                return true;
    return false;
}

und eine kleine backupGlobals Funktion geändert:

foreach (array_keys($GLOBALS) as $key) {
    if ($key != 'GLOBALS' &&
        !in_array($key, $superGlobalArrays) &&
        !in_array($key, $blacklist) &&
        !PHPUnit_Util_GlobalState::checkIfThereIsClosureInIt($GLOBALS[$key])
//        !$GLOBALS[$key] instanceof Closure
    ) {
        self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]);
    }
}

diese Version scheint zu funktionieren (ich erwische diese Ausnahme nicht mehr).
Da es sich um eine Rekursion gegen $GLOBALS handelt, kann es der CPU etwas mehr Wärme geben.

Der obige Code-Fix von stafr hat die PHPunit-Probleme behoben, die ich mit den Ausnahmen "Serialization of Closure" hatte. Vielen Dank!

Ich erhalte dieselbe Fehlermeldung, wenn ich ein new MyRestClient() instanziiere, dessen Konstruktor $this->client = new \GuzzleHttp\Client(); . Es ist auch dasselbe, als ich versucht habe, im Konstruktor meiner Klasse $x=function(){}; . Ich denke, der Guzzle-Client macht intern etwas Ähnliches. Dies macht es unmöglich, jemals innerhalb eines phpunit-Tests zu instanziieren. jetzt bin ich so traurig :schluchz:

Füge nur meine Erfahrung hinzu. Grundsätzlich wird phpunit Serialization of 'Closure' is not allowed oder Serialization of 'class<strong i="6">@anonymous</strong>' is not allowed ausgeben, wenn Sie eine anonyme Funktion oder Klasse als Testklassenattribut angeben. Wenn Sie also eine anonyme Funktion oder Klasse verwenden müssen, stellen Sie sicher, dass es sich um eine einmalige Variable handelt und nicht um das Klassenattribut.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen