PHPUnit загружает все классы одновременно. Вызывает PHP Неустранимая ошибка: не удается переопределить класс

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

У меня есть ситуация, когда мой PHP-код генерирует определения классов на основе свойств конфигурации.

Определения классов являются в основном владельцами данных и могут иметь:

  • общественные объекты
  • или защищенные свойства с открытым интерфейсом, который поставляет геттер / сеттеры.

В некоторых случаях конфигурации генерируемые имена кланов будут одинаковыми, но их ИМЯ ФАЙЛА БУДЕТ РАЗЛИЧНЫМИ. В реальной среде пользователь просто генерирует один набор определений классов на основе требуемой конфигурации и использует классы в своем приложении. Там нет проблем, даже если пользователь создает несколько наборов определений классов. PHP будет с радостью работать, если в приложении указывается только один набор определений.

У меня есть два тестовых примера PHPUnit, где я делаю в основном те же тесты, используя классы с разными определениями, сгенерированными любой конфигурацией. Я использую «require_once» во всем моем коде и делаю то же самое в модульных тестах, «require_once» использует только файлы классов, которые мне нужны для этого теста.

PHPUnit настроен для запуска всех тестов, которые он находит в моем тестовом каталоге, и работает как обычно. Когда я добавил тесты для генерации разных классов, PHPUnit перестала работать с ошибкой PHP Fatal: нельзя переопределять класс.

Теперь поведение PHPUnit по умолчанию состоит в том, чтобы загрузить ВСЕ классы, для которых ВСЕ тесты должны выполняться за один раз. Это приводит к фатальной ошибке PHP даже до запуска любого теста, потому что PHPUnit выбирает второе определение для сгенерированных классов (они имеют одно и то же имя класса, но разные имена файлов), хотя у меня есть только «require_once» правильные определения классов в каждом файл теста.

Я все еще могу запускать тесты, но только с одним тестовым файлом за раз, поэтому в настоящее время я должен запускать все свои тесты либо вручную, либо командным файлом. Полный отчет о покрытии кода во всех тестах невозможен.

Мне хотелось бы, чтобы PHPUnit загружал только те классы, которые были «require_once» для каждого тестового файла, а не для всех тестовых файлов, которые он видит, которые запускаются из конфигурации phpunit.xml. Или лучше всего, чтобы PHPUnit загружал только свои собственные классы для всех указанных тестов и оставлял сам PHP для выполнения пользователями «require_once» для каждого теста.

Есть ли способ обойти это? Я просмотрел настройки конфигурации PHPUnit, но ни один из них не соответствует конкретной проблеме. Я не очень хорошо знаком с PHPUnit под обложками, поэтому создание другого загрузчика для тестирования будет сложным.

Вероятно, лучше всего сделать простой пример. Вот пара тестовых файлов 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 не будет запускать тесты в testuite, потому что он попытался загрузить все классы, необходимые для всего теста, перед тем, как он выполнит любые тесты.

К моему способу мышления PHPUnit делает не то, что происходит здесь, подбирая зависимости, которые он не должен выполнять для конкретного теста.