Хотя $GLOBAL
Closures больше не сериализуются с 01aa34783c9b19d39e568641f3f2dd0fc983b11a & # 352, массив $GLOBAL
который содержит Closure в качестве значения, все равно вызовет ошибку «Сериализация 'Closure' не разрешена».
$GLOBALS[] = array( 'foo' => function() { return 'bar'; } );
У некоторых людей, в том числе у меня, возникла эта проблема. 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
. Итак, если вам нужно использовать анонимную функцию или класс, убедитесь, что это одноразовая переменная, а не атрибут тестового класса.
Самый полезный комментарий
У меня такое же сообщение об ошибке появляется всякий раз, когда я создаю экземпляр
new MyRestClient()
, конструктор которого содержит$this->client = new \GuzzleHttp\Client();
. То же самое, когда я пытался использовать$x=function(){};
в конструкторе своего класса. Я предполагаю, что клиент Guzzle делает что-то похожее внутри. Это делает невозможным создание экземпляра из теста phpunit. Мне сейчас так грустно: sob: