Phpunit: A serialização de 'Encerramento' não é permitida

Criado em 2 jan. 2012  ·  12Comentários  ·  Fonte: sebastianbergmann/phpunit

Embora $GLOBAL Fechamentos não sejam mais serializados desde 01aa34783c9b19d39e568641f3f2dd0fc983b11a & # 352 uma matriz $GLOBAL que contenha um Fechamento como valor ainda causará o erro "A serialização de 'Fechamento' não é permitida".

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

Comentários muito úteis

Eu recebo a mesma mensagem de erro sempre que instanciar um new MyRestClient() , cujo construtor contém $this->client = new \GuzzleHttp\Client(); . Também é o mesmo quando tentei usar um $x=function(){}; no construtor da minha classe. Acho que o cliente Guzzle faz algo semelhante internamente. Isso torna impossível criar uma instância de dentro de um teste phpunit. Estou tão triste agora: soluço:

Todos 12 comentários

Outro caso que estou conseguindo

 / * test.php * /
 classe closureTest estende PHPUnit_Framework_TestCase
 {
 function testClosure () {
 $ this-> assertEquals (1, 1);
 call_user_func (function ($ a) {
 lance novo \ Exception ("teste");
 }, 10);
 $ this-> assertEquals (2, 2);
 }
 }

e, em seguida, execute-o no isolamento do processo

 phpunit --process-isolation test.php

você iria conseguir

 Houve 1 erro:
 1) phTest :: testClosure
 PHPUnit_Framework_Exception: Erro fatal de PHP: exceção não detectada 'Exceção' com a mensagem 'A serialização de' Fechamento 'não é permitida' em -: 37
 Rastreamento de pilha:
 # 0 - (37): serializar (matriz)
 # 1 - (123): __phpunit_run_isolated_test ()
 # 2 {main}
 jogado - na linha 37
 FALHAS!
 Testes: 1, Asserções: 0, Erros: 1.

Eu estava tendo o mesmo problema ao usar o isolamento do processo, para contornar isso adicionei __sleep ao meu testCase e limpei os fechamentos lá. Para mim, eu tinha armazenado alguns mocks nas propriedades do testcase, então a culpa foi minha, realmente, espero que isso ajude alguém.

Também estou tendo o mesmo problema e posso replicar o problema @tmilos mencionado anteriormente. Não sei se este tíquete morreu, mas seria bom se pudéssemos resolver isso. Estou mais do que disposto a fazer uma solicitação de pull, se isso for preferível.

Solicitações de pull são sempre apreciadas!

Eu sei que tem sido um pouco, mas eu estive fora do projeto por um tempo. Na sequência do comentário de

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

Observe a falta de um argumento fornecido no final de call_user_func . A exceção de serialização resulta da tentativa de serializar o objeto PHPUnit_Framework_TestResult. Esta tentativa de serialização pode ser encontrada na linha 42 de PHPUnit/Framework/Process/TestCaseMethod.tpl.dist . A parte ofensiva do objeto a ser serializado é uma referência de fechamento na hierarquia de rastreamento da Exceção que foi lançada:

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

)

Minha pergunta então, como esta é minha primeira vez corrigindo o PHPUnit, é curto de remover o fechamento ou modificá-lo para ser benigno - o que envolveria o uso de Reflection, sem dúvida - há alguma forma de melhor prática do PHPUnit para lidar com isso ? Alguma ideia ou opinião, pelo menos?

Além disso, escrevi um teste em Regressions / GitHub. Isso é aceitável?

@kunjalpopat , em referência ao seu problema, A primeira coisa que eu verificaria são as exceções. Quando em isolamento de processo, as exceções lançadas podem fornecer uma mensagem de "Serialização de fechamento". Tente embrulhar seu código de teste em um try / catch e veja se isso corrige o problema, se corrigir, então você pode querer reduzir a cobertura do try / catch até encontrar a área do problema.

O problema está em 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]);
}

Eu inventei um ajudante em 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;
}

e mudou um pouco a função 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 versão parece estar funcionando (não entendo mais essa exceção).
Como é uma recursão contra $ GLOBALS, pode dar um calor extra à cpu.

A correção do código acima do stafr corrigiu os problemas do PHPunit que eu estava tendo com as exceções de "Serialização de fechamento". Muito Obrigado!

Eu recebo a mesma mensagem de erro sempre que instanciar um new MyRestClient() , cujo construtor contém $this->client = new \GuzzleHttp\Client(); . Também é o mesmo quando tentei usar um $x=function(){}; no construtor da minha classe. Acho que o cliente Guzzle faz algo semelhante internamente. Isso torna impossível criar uma instância de dentro de um teste phpunit. Estou tão triste agora: soluço:

Apenas adicionando minha experiência. Basicamente, sempre que você colocar uma função ou classe anônima como atributo de classe de teste, o phpunit irá lançar Serialization of 'Closure' is not allowed ou Serialization of 'class<strong i="6">@anonymous</strong>' is not allowed . Portanto, se você precisar usar uma função ou classe anônima, certifique-se de que seja uma variável única, não teste o atributo de classe.

Esta página foi útil?
0 / 5 - 0 avaliações