Phpunit: No se permite la serialización de 'Cierre'

Creado en 2 ene. 2012  ·  12Comentarios  ·  Fuente: sebastianbergmann/phpunit

Aunque los cierres $GLOBAL ya no se serializan desde 01aa34783c9b19d39e568641f3f2dd0fc983b11a & # 352 una matriz $GLOBAL que contiene un cierre como valor seguirá causando el error "No se permite la serialización de 'cierre'".

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

Comentario más útil

Tengo este mismo mensaje de error cada vez que creo una instancia de new MyRestClient() , cuyo constructor contiene $this->client = new \GuzzleHttp\Client(); . También es lo mismo cuando intenté usar $x=function(){}; en el constructor de mi clase. Supongo que el cliente de Guzzle hace algo similar internamente. Esto hace que sea imposible crear una instancia desde dentro de una prueba phpunit. Estoy tan triste ahora: sollozo:

Todos 12 comentarios

Otro caso lo estoy consiguiendo

 / * prueba.php * /
 class ClosingTest extiende PHPUnit_Framework_TestCase
 {
 function testClosure () {
 $ esto-> assertEquals (1, 1);
 call_user_func (función ($ a) {
 lanzar nueva \ Exception ("prueba");
 }, 10);
 $ esto-> assertEquals (2, 2);
 }
 }

y luego ejecutarlo en aislamiento de proceso

 phpunit --proceso-aislamiento test.php

obtendrías

 Hubo 1 error:
 1) phTest :: testClosure
 PHPUnit_Framework_Exception: Error fatal de PHP: Excepción no detectada 'Excepción' con el mensaje 'No se permite la serialización de' Cierre 'en -: 37
 Seguimiento de pila:
 # 0 - (37): serializar (matriz)
 # 1 - (123): __phpunit_run_isolated_test ()
 # 2 {principal}
 arrojado - en la línea 37
 ¡FALLOS!
 Pruebas: 1, afirmaciones: 0, errores: 1.

Estaba teniendo el mismo problema al usar el aislamiento de procesos, para solucionarlo agregué __sleep a mi testCase y limpié los cierres allí. Para mí, había almacenado algunas simulaciones en las propiedades del caso de prueba, por lo que realmente fue mi culpa, espero que esto ayude a alguien.

También tengo el mismo problema y puedo replicar el problema @tmilos mencionado anteriormente. No sé si este boleto está muerto, pero sería bueno si pudiéramos resolver esto. Estoy más que dispuesto a incluir una solicitud de extracción si es preferible.

¡Las solicitudes de extracción siempre son apreciadas!

Sé que ha sido un poco, pero estuve fuera del proyecto por un tiempo. Además del comentario de @tmilos , puedo replicar el problema si

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

Tenga en cuenta la falta de un argumento proporcionado al final de call_user_func . La excepción de serialización resulta del intento de serializar el objeto PHPUnit_Framework_TestResult. Este intento de serialización se puede encontrar en la línea 42 de PHPUnit/Framework/Process/TestCaseMethod.tpl.dist . La parte ofensiva del objeto que se va a serializar es una referencia de cierre en la jerarquía de seguimiento de la excepción que se lanzó:

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

)

Entonces, mi pregunta, ya que esta es la primera vez que parcheo PHPUnit, no llega a eliminar el cierre o modificarlo para que sea benigno, lo que sin duda implicaría el uso de Reflection, ¿hay alguna forma de mejores prácticas de PHPUnit para lidiar con esto? ? ¿Alguna idea o aportación al menos?

Además, escribí una prueba en Regressions / GitHub. ¿Es esto aceptable?

@kunjalpopat , en referencia a su problema, lo primero que comprobaría son las excepciones. Cuando está en proceso de aislamiento, las excepciones lanzadas pueden darle un mensaje de "Serialización del cierre". Intente envolver su código de prueba en un try / catch y vea si eso soluciona el problema, si lo hace, entonces puede buscar recortar la cobertura del try / catch hasta que encuentre el área del problema.

El problema radica en 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]);
}

He inventado un ayudante en 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;
}

y cambió una pequeña función backupGlobals :

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

esta versión parece estar funcionando (ya no capto esa excepción).
Dado que es una recursividad contra $ GLOBALS, puede darle un poco de calor adicional a la cpu.

La corrección de código anterior de stafr solucionó los problemas de PHPunit que estaba teniendo con las excepciones de "Serialización del cierre". ¡Muchas gracias!

Tengo este mismo mensaje de error cada vez que creo una instancia de new MyRestClient() , cuyo constructor contiene $this->client = new \GuzzleHttp\Client(); . También es lo mismo cuando intenté usar $x=function(){}; en el constructor de mi clase. Supongo que el cliente de Guzzle hace algo similar internamente. Esto hace que sea imposible crear una instancia desde dentro de una prueba phpunit. Estoy tan triste ahora: sollozo:

Solo agrego mi experiencia. Básicamente, siempre que ponga una función o clase anónima como atributo de clase de prueba, phpunit arrojará Serialization of 'Closure' is not allowed o Serialization of 'class<strong i="6">@anonymous</strong>' is not allowed . Por lo tanto, si necesita usar una función o clase anónima, asegúrese de que sea una variable única, no un atributo de clase de prueba.

¿Fue útil esta página
0 / 5 - 0 calificaciones