Решение проблемы расхода памяти PHPUnit & Zend_Test для Zend Framework веб-приложения

На работе часть команды занимается написанием тестов для веб-приложения на Zend Framework. Надо сказать, что фреймворк довольно тяжелый, а уж в режиме тестов тем более (т.к. один процесс в этом режиме обрабатывает не один HTTP-запрос, как в обычном режиме, а целую кучу). Раньше всё было хорошо, но постепенно тестов становилось всё больше и больше, они начали интенсивно кушать память и в один прекрасный момент перестали работать совсем.Мы увеличивали лимиты (memory_limit) но потом они стали совсем уж большими (512Мб). В системе тестирования то и дело вываливались ошибки типа этой:

Allowed memory size of 33554432 bytes exhausted.

Сокращение расхода памяти в phpUnit

Поэтому стало ясно, что надо что-то менять. Погуглив данную тему, я узнал о специальном режиме работы PHPUnit – “processIsolation”. Смотрим в мануалку:

–process-isolation Run each test in a separate PHP process.

Ага, каждый тест запускается в отдельном процессе. А значит, он уж точно влезет в лимит ( ну если конечно мы не сделаем мега-тест на пол-гигабайта 🙂 ). Чтобы активировать этот режим нужно либо добавить параметр при запуске phpunit (см. выше), либо дописать его в phpunit.xml файл.

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<phpunit bootstrap=”./application/bootstrap.php”
colors=”true”
convertErrorsToExceptions=”true”
convertNoticesToExceptions=”true”
convertWarningsToExceptions=”true”
processIsolation=true”
stopOnFailure=”true”
syntaxCheck=”true”>

Запустили его, и теперь расход памяти уменьшился, а тесты стали проходить.

Note1: Текущее состояние (currentState) в режиме изоляции процессов phpUnit

Тут надо отметить, что в режиме работы с изоляцией процессов могут происходить некоторые проблемы с инклюдами. Это связано с параметром $this->preserveGlobalState класса контроллера. Вот что видно в исходниках:</p> <pre class=”> $template->setVar(
array(

‘included_files’ => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getIncludedFilesAsString() : ”,
‘constants’ => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getConstantsAsString() : ”,
‘globals’ => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getGlobalsAsString() : ”,

)
);

А т.к. переменная preserveGlobalState по-умолчанию true:

то нам надо перопределить её.

Однако, у меня, вс1 было с точностью наоборот. Т.е. проблемы с инклюдами возникли после становки в false этого параметра.

Note2: Циклические ссылки и тесты

При наличии циклических ссылок, вас спасет флаг –no-globals-backup . Он отключает бэкап+рестор “глобальных” переменных при запуске теста. Опасно, но помогает при наличии в программе случайных циклических ссылок – как в PEAR, например.

Литература

http://stackoverflow.com/questions/4216027/phpunit-with-zend-framework-memory-problem
http://matthewturland.com/2010/08/19/process-isolation-in-phpunit/

http://friendfeed.com/dklab/fc835155/phpunit-php-fatal-error-allowed-memory-size-of

Leave a Comment