Phpunit: Сериализация Closure не допускается.

Созданный на 2 янв. 2012  ·  12Комментарии  ·  Источник: sebastianbergmann/phpunit

Хотя $GLOBAL Closures больше не сериализуются с 01aa34783c9b19d39e568641f3f2dd0fc983b11a & # 352, массив $GLOBAL который содержит Closure в качестве значения, все равно вызовет ошибку «Сериализация 'Closure' не разрешена».

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

Самый полезный комментарий

У меня такое же сообщение об ошибке появляется всякий раз, когда я создаю экземпляр new MyRestClient() , конструктор которого содержит $this->client = new \GuzzleHttp\Client(); . То же самое, когда я пытался использовать $x=function(){}; в конструкторе своего класса. Я предполагаю, что клиент Guzzle делает что-то похожее внутри. Это делает невозможным создание экземпляра из теста phpunit. Мне сейчас так грустно: sob:

Все 12 Комментарий

У некоторых людей, в том числе у меня, возникла эта проблема. http://stackoverflow.com/questions/4366592/symfony-2-doctrine-2-phpunit-3-5-serialization-of-closure-exception

Другой случай, я понимаю

 / * test.php * /
 class closureTest расширяет PHPUnit_Framework_TestCase
 {
 function testClosure () {
 $ this-> assertEquals (1, 1);
 call_user_func (функция ($ a) {
 выбросить новое \ исключение ("тест");
 }, 10);
 $ this-> assertEquals (2, 2);
 }
 }

а затем запустить его в изоляции процесса

 phpunit --process-изоляция test.php

вы бы получили

 Произошла 1 ошибка:
 1) phTest :: testClosure
 PHPUnit_Framework_Exception: Неустранимая ошибка PHP: Неперехваченное исключение «Исключение» с сообщением «Сериализация« Закрытие »не разрешена» в -: 37
 Трассировки стека:
 # 0 - (37): сериализовать (массив)
 # 1 - (123): __phpunit_run_isolated_test ()
 # 2 {main}
 вброшено - в строке 37
 ОТКАЗЫ!
 Тестов: 1, утверждений: 0, ошибок: 1.

У меня была такая же проблема при использовании изоляции процесса, чтобы обойти ее, я добавил __sleep в свой testCase и очистил там закрытие. Что касается меня, я сохранил некоторые mocks в свойствах testcase, так что это действительно была моя собственная ошибка, я надеюсь, что это кому-то поможет.

У меня такая же проблема, и я могу повторить проблему @tmilos, упомянутую ранее. Я не знаю, мертв ли ​​этот билет, но было бы неплохо, если бы мы могли решить эту проблему. Я более чем готов поставить пул-реквест, если это предпочтительнее.

Запросы на вытягивание всегда приветствуются!

Я знаю, что это было немного, но какое-то время я был вне проекта. В дополнение к комментарию @tmilos , я могу воспроизвести проблему, если я

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

Обратите внимание на отсутствие аргумента в конце call_user_func . Исключение сериализации является результатом попытки сериализации объекта PHPUnit_Framework_TestResult. Эту попытку сериализации можно найти в строке 42 PHPUnit/Framework/Process/TestCaseMethod.tpl.dist . Неприятная часть сериализуемого объекта - это ссылка на закрытие в иерархии трассировки сгенерированного исключения:

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

)

Тогда мой вопрос, поскольку это мой первый патч PHPUnit, заключается в том, чтобы удалить закрытие или изменить его, чтобы он был в противном случае неопасным - что, без сомнения, потребует использования Reflection - есть ли какой-либо способ PHPUnit-best-практика справиться с этим ? По крайней мере, есть какие-нибудь мысли или предложения?

Также я написал тест в разделе Regressions / GitHub. Это приемлемо?

@kunjalpopat , что касается вашей проблемы, первое, что я бы проверил, это исключения. Когда процесс находится в изоляции, возникшие исключения могут дать вам сообщение «Сериализация закрытия». Попробуйте обернуть свой тестовый код в try / catch и посмотреть, решит ли это проблему, если да, то вы можете посмотреть на сокращение охвата try / catch, пока не найдете проблемную область.

Проблема заключается в 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]);
}

Я придумал помощника в 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;
}

и немного изменил функцию 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]);
    }
}

эта версия, похоже, работает (я больше не улавливаю это исключение).
Поскольку это рекурсия по отношению к $ GLOBALS, это может вызвать дополнительную нагрузку на процессор.

Приведенное выше исправление кода от stafr устраняет проблемы PHPunit, которые у меня возникали с исключениями «Сериализация закрытия». Большое спасибо!

У меня такое же сообщение об ошибке появляется всякий раз, когда я создаю экземпляр new MyRestClient() , конструктор которого содержит $this->client = new \GuzzleHttp\Client(); . То же самое, когда я пытался использовать $x=function(){}; в конструкторе своего класса. Я предполагаю, что клиент Guzzle делает что-то похожее внутри. Это делает невозможным создание экземпляра из теста phpunit. Мне сейчас так грустно: sob:

Просто добавляю свой опыт. Обычно всякий раз, когда вы помещаете анонимную функцию или класс в качестве атрибута тестового класса, phpunit выдает Serialization of 'Closure' is not allowed или Serialization of 'class<strong i="6">@anonymous</strong>' is not allowed . Итак, если вам нужно использовать анонимную функцию или класс, убедитесь, что это одноразовая переменная, а не атрибут тестового класса.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги