PHPUnit загружает все классы одновременно. Вызывает фатальную ошибку PHP: не удается переопределить класс
Я сделал все возможное, но я не думаю, что какие-либо вопросы касались этой проблемы.
У меня есть ситуация, когда мой код PHP генерирует определения классов на основе свойств конфигурации.
Определения классов в основном являются держателями данных и могут иметь:
- общественная собственность
- или защищенные свойства с открытым интерфейсом, который предоставляет геттер / сеттеры.
В определенных случаях конфигурации сгенерированные ИМЯ КЛАССА БУДУТ ЖЕ, но их ИМЕНА ФАЙЛА БУДУТ РАЗНЫМИ. В реальной среде пользователь просто генерирует единый набор определений классов на основе требуемой конфигурации и использует классы в своем приложении. Нет проблем, даже если пользователь генерирует несколько наборов определений классов. PHP будет радостно работать, если в приложении есть только один набор определений.
У меня есть два тестовых случая PHPUnit, в которых я делаю в основном одни и те же тесты, используя классы с разными определениями, сгенерированными любой конфигурацией. Я использую "require_once" во всем своем коде и делаю то же самое в модульных тестах, "require_once", используя только те файлы классов, которые мне нужны для этого теста.
PHPUnit настроен для запуска всех тестов, которые он находит в моем каталоге тестов и работает в обычном режиме. Когда я добавил тесты для разных поколений классов, PHPUnit перестал работать с фатальной ошибкой PHP: невозможно повторно объявить класс.
Теперь поведение PHPUnit по умолчанию, по-видимому, заключается в загрузке ВСЕХ классов, которые ВСЕ тесты должны запускать за один раз. Это приводит к фатальной ошибке PHP даже до запуска любого теста, потому что PHPUnit выбирает второе определение для сгенерированных классов (они имеют одинаковое имя класса, но разные имена файлов), хотя я только "require_once" редактировал правильные определения классов в каждом тестовый файл.
Я все еще могу запускать тесты, но только с одним тестовым файлом за раз, поэтому в настоящее время я должен запускать все свои тесты вручную или с помощью пакетного файла. Полный отчет о покрытии кода по всем тестам невозможен.
Мне хотелось бы, чтобы PHPUnit загружал только те классы, которые были "require_once" ed для каждого тестового файла, а не для всех тестовых файлов, которые он видит как запускаемые из конфигурации phpunit.xml. Или лучшим способом было бы для PHPUnit загружать свои собственные классы только для всех указанных тестов и оставлять PHP самому, чтобы пользователь "require_once" выполнял каждый тест.
Есть ли способ обойти это? Я посмотрел на параметры конфигурации PHPUnit, но ни один из них не подходит для конкретной проблемы. Я не очень знаком с PHPUnit под прикрытием, поэтому создание другого загрузчика testsuite будет затруднительным.
Вероятно, лучше сделать простой пример. Вот несколько тестовых файлов PHPUnit foo1Test.php и foo2test.php. Единственное различие между ними заключается в том, что они требуют_ другого файла класса, который имеет определение класса Foo. Неважно, что все эти классы пусты, все они совершенно законны, и это хорошо демонстрирует проблему. Я просто поместил все эти файлы в каталог testfoo и запустил на них PHPunit. Вы можете сделать это тоже, и вы получите тот же результат.
foo1Test.php
<?php
require_once dirname ( __FILE__ ).'/Foo1.php';
class Foo1TestCase extends PHPUnit_Framework_TestCase
{
}
?>
foo2Test.php
<?php
require_once dirname ( __FILE__ ).'/Foo2.php';
class Foo2TestCase extends PHPUnit_Framework_TestCase
{
}
?>
Foo1.php
<?php
class Foo
{
}
?>
Foo2.php
<?php
class Foo
{
}
?>
Два тестовых файла foo1Test.php и foo2Test.php являются совершенно корректными файлами и выполняются через следующие командные строки PHPunit.
phpunit foo1Test.php
phpunit foo2Test.php
Как и следовало ожидать, PHPUnit терпит неудачу, жалуясь на отсутствие тестов, что хорошо.
У меня также есть стандартный файл конфигурации phpunit.xml, который будет запускать все тесты в текущем каталоге.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupStaticAttributes="false"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
mapTestClassNameToCoveredClassName="false"
printerClass="PHPUnit_TextUI_ResultPrinter"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader"
strict="false"
verbose="true">
<testsuite name="fooTests">
<directory>.</directory>
</testsuite>
</phpunit>
Я запустил PHPUnit с этим конфигом следующим образом
PHPUnit
Выход:
PHP Fatal error: Cannot redeclare class Foo in /var/www/testfoo/Foo2.php on line 4
PHP Stack trace:
PHP 1. {main}() /usr/bin/phpunit:0
PHP 2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP 3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:130
PHP 4. PHPUnit_TextUI_Command->handleArguments() /usr/share/php/PHPUnit/TextUI/Command.php:139
PHP 5. PHPUnit_Util_Configuration->getTestSuiteConfiguration() /usr/share/php/PHPUnit/TextUI/Command.php:671
PHP 6. PHPUnit_Util_Configuration->getTestSuite() /usr/share/php/PHPUnit/Util/Configuration.php:768
PHP 7. PHPUnit_Framework_TestSuite->addTestFiles() /usr/share/php/PHPUnit/Util/Configuration.php:848
PHP 8. PHPUnit_Framework_TestSuite->addTestFile() /usr/share/php/PHPUnit/Framework/TestSuite.php:419
PHP 9. PHPUnit_Util_Fileloader::checkAndLoad() /usr/share/php/PHPUnit/Framework/TestSuite.php:358
PHP 10. PHPUnit_Util_Fileloader::load() /usr/share/php/PHPUnit/Util/Fileloader.php:79
PHP 11. include_once() /usr/share/php/PHPUnit/Util/Fileloader.php:95
PHP 12. require_once() /var/www/testfoo/foo2Test.php:3
Вот о чем этот вопрос. Хотя тестовые файлы совершенно допустимы в отдельности, PHPUnit не будет запускать тесты под тестовым набором, потому что он пытался загрузить все классы, необходимые для всего тестового набора, ДО того, как он выполнит какие-либо тесты.
На мой взгляд, PHPUnit делает не то, что нужно, выбирая зависимости, которых не должно быть для конкретного теста.