Ошибка ‘Cannot redeclare class’ при запуске теста PHPUnit

Как избавиться от ошибки ‘Cannot redeclare class’ при выполнение теста PHPUnit? Разберем причины и способы устранения.

Ошибка подобного рода может возникать когда при выполнении набора тестов один из классов определяется более 1 раза. Такое может возникнуть при выполнении интеграционных тестов.

Рассмотрим пример простого интеграционного теста на Zend Framework:


public function testValidateUserSuccess()
{
    $this->getRequest()
        ->setMethod('POST')
        ->setPost(array('username' => 'test', 'msisdn' => '375291234567'));

    $this->dispatch('/api/user/validate');
    $this->assertResponseCode(200);
}

public function testValidateUserFailure()
{
    $this->getRequest()
        ->setMethod('POST')
        ->setPost(array('username' => 'test', 'msisdn' => 'abc'));

    $this->dispatch('/api/user/validate');
    $this->assertResponseCode(400);
}

При выполнении данного набора тестов приложение будет запущено дважды, а значит дважды ининицализируются все методы Bootstrap‘а и Autoloader.
Один из вариантов решения — это запуск теста в отдельном процессе. Для этого необходимо добавить перед тестом @runInSeparateProcess.


/**
 * @runInSeparateProcess
 */
public function testValidateUserSuccess()
{
    ...
}

/**
 * @runInSeparateProcess
 */
public function testValidateUserFailure()
{
    ...
}

Можно запустить каждый тест в отдельном процессе, указав перед классом теста @runTestsInSeparateProcesses


/**
 * @runTestsInSeparateProcesses
 **/
class UserTest extends PHPUnit_Framework_TestCase
{
    public function testValidateUserSuccess()
    {
        ...
    }

    public function testValidateUserFailure()
    {
        ...
    }
}

Подводные камни

Во время запуска тестов я периодически ловил ошибку


RuntimeException: PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in -:36

Полный текст ошибки


PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /path/to/project/tests/phpunit.xml

E

Time: 0 seconds, Memory: 4.50Mb

There was 1 error:

1) UserTest::testValidateUserSuccess
RuntimeException: PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in -:36
Stack trace:
#0 -(36): serialize(Array)
#1 -(135): __phpunit_run_isolated_test()
#2 {main}
  thrown in - on line 36

Гуглил, нашел пару предположений:

  • PHPUnit пытается все сложить в переменную $GLOBALS и ошибка возникает когда в тесте есть замыкания. Фикс: не использовать замыкания. Не мой вариант — у меня замыканий не было.
  • Причина @runInSeparateProcess. Фикс: не используйте @runInSeparateProcess. Однозначно тоже не мой вариант.

Не сумев найти решения на просторах интернета, я решил обновить PHPUnit с 3.6.10 => 4.7.7 — помогло 🙂
P.S. совместимость Zend Framework 1.12.13 с PHPUnit 4.7 нормальная (несмотря на заявленную поддержку 3.7).

Stas Kuryan

Web developer. Перфекционист в написании кода.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *