В настоящее время я собираюсь начать с нуля с помощью тестов phpunit для проекта. Поэтому я изучал некоторые проекты (например, Zend), чтобы посмотреть, как они делают вещи и как они организуют свои тесты.
Большинство вещей довольно ясны, только у меня есть некоторые проблемы с тем, как правильно организовать тестовые пакеты. Zend имеет AllTests.php, из которого загружаются другие тестовые сеты.
Тщательно глядя на класс, он использует PHPUnit_Framework_TestSuite
для создания объекта набора, а затем добавляет к нему другие пакеты, но если я посмотрю в документах PHPUnit для организации тестов в версиях PHPUnit после 3.4, то есть только описание для XML или FileHierarchy. Тот, который использовал классы для организации тестов, был удален.
Я не нашел ничего, что этот метод устарел, и проекты, подобные Zend, все еще используют его.
Но если он устарел, как я смогу организовать тесты в одной структуре с конфигурацией xml? Выполнение всех тестов не проблема, но как бы я организовал тесты (в xml), если бы я только хотел выполнить несколько тестов. Может быть, создание нескольких xmls, где я только укажу несколько тестов / тестовых наборов для запуска?
Поэтому, если бы я хотел только протестировать module1 и module2 приложения, у меня будет дополнительный xml для каждого и определение наборов тестов только для тех модулей (классов, используемых модулем) в нем. А также тот, который определяет набор тестов для всех тестов?
Или было бы лучше использовать аннотацию @group
для конкретных тестов, чтобы отметить их для модуля 1 или модуля2?
Заранее благодарим за то, что вы указали мне некоторые лучшие практики.
Я начну с ссылки на руководство, а затем перейду к тому, что я видел и слышал в поле.
Организация наборов тестов phpunit
Мой рекомендуемый подход сочетает файловую систему с xml-конфигурацией.
tests/ \ unit/ | - module1 | - module2 - integration/ - functional/
с phpunit.xml
с простым:
<testsuites> <testsuite name="My whole project"> <directory>tests</directory> </testsuite> </testsuites>
во<testsuites> <testsuite name="My whole project"> <directory>tests</directory> </testsuite> </testsuites>
вы можете разделить testuites, если хотите, но это проект для выбора проекта.
Запуск phpunit
затем выполнит ВСЕ тесты, а запущенные phpunit tests/unit/module1
будут запускать все тесты модуля1.
Наиболее распространенный подход здесь заключается в том, чтобы отразить структуру source/
каталога в структуре ваших tests/unit/
папок.
У вас есть один TestClass на ProductionClass, так что это хороший подход в моей книге.
Это не будет работать в любом случае, если у вас более одного тестового класса в одном файле, чтобы избежать этой ошибки.
Это просто делает запись теста более подробной, так как вам нужен дополнительный оператор использования, поэтому я бы сказал, что testClass должен находиться в том же пространстве имен, что и производственный класс, но это ничего не делает, что PHPUnit заставляет вас делать. Я просто нашел, что это проще, без каких-либо недостатков.
Например, phpunit --filter Factory
выполняет все FactoryTests, в то время как phpunit tests/unit/logger/
выполняет все связанные с phpunit --filter Factory
.
Вы можете использовать теги @group
для чего-то вроде номеров выпуска, рассказов или чего-то, но для «модулей» я бы использовал макет папки.
Может быть полезно создать несколько xml-файлов, если вы хотите:
their phpunit.xmls
Поскольку это связано с запуском нового проекта с тестами:
@covers
как описано в моем блоге (Только для модульных тестов, всегда охватывайте все непубличные функции, всегда используйте теги покрытий. Вам не нужна какая-либо автоматическая загрузка для ваших тестов. PHPUnit позаботится об этом.
Используйте <phpunit bootstrap="file">
чтобы указать свой тестовый бутстрап. tests/bootstrap.php
– это отличное место для его размещения. Там вы можете настроить автозагрузчик приложений и т. Д. (Или вызывать загрузку приложений в этом случае).
phpunit --filter
или phpunit tests/unit/module1
strict
режим от выхода и никогда не выключайте его. Основная структура каталогов :
Я экспериментировал с сохранением тестового кода рядом с тестируемым кодом, буквально в том же каталоге, с немного отличающимся именем файла от файла с кодом, который он тестирует. Пока мне нравится этот подход. Идея заключается в том, что вам не нужно тратить время и энергию на сохранение структуры каталогов между вашим кодом и вашим тестовым кодом. Поэтому, если вы измените имя каталога, в котором находится код, вам также не нужно искать и изменять имя каталога для тестового кода. Это также заставляет вас тратить меньше времени на поиск тестового кода, который идет с некоторым кодом, так как он находится рядом с ним. Это даже затрудняет создание файла с помощью тестового кода, потому что вам не нужно сначала находить каталог с тестами, возможно создать новый каталог, соответствующий тому, для которого вы создаете тесты, и затем создайте тестовый файл. Вы просто создаете тестовый файл прямо там.
Одно огромное преимущество этого – это значит, что другие сотрудники (а не вы, потому что вы никогда этого не сделаете) будут с меньшей вероятностью избегать написания тестового кода, потому что это слишком много работы. Даже когда они добавляют методы к существующим классам, они с меньшей вероятностью не захотят добавлять тесты к существующему тестовому коду.
Одним из недостатков является то, что это затрудняет выпуск вашего производственного кода без сопровождающих его тестов. Хотя, если вы используете жесткие соглашения об именах, это все равно возможно. Например, я использовал ClassName.php, ClassNameUnitTest.php и ClassNameIntegrationTest.php. Когда я хочу запустить все модульные тесты, есть набор, который ищет файлы, заканчивающиеся на UnitTest.php. Сетка тестирования интеграции работает аналогичным образом. Если бы я хотел, я мог бы использовать подобный метод, чтобы предотвратить выпуск тестов на производство.
Другим недостатком этого подхода является то, что когда вы просто ищете фактический код, а не тестовый код, требуется немного больше усилий, чтобы различать эти два.
Один класс тестов для каждого класса:
Это далеко не экспериментально для большинства программистов, но это для меня. Я экспериментирую, имея только один тестовый класс для каждого тестируемого класса. Раньше у меня был целый каталог для каждого тестируемого класса, а затем у меня было несколько классов внутри этого каталога. Каждый тестовый класс настраивает тестируемый класс определенным образом, а затем имеет кучу методов, каждый из которых имеет другое утверждение. Но затем я начал замечать определенные условия, чтобы эти объекты были связаны с другими условиями, которые он попал в другие классы тестов. Дублирование становится слишком сильным, поэтому я начал создавать абстракции, чтобы удалять его. Тестовый код стал очень трудно понять и поддерживать. Я понял это, но я не видел альтернативы, которая имела смысл для меня. Просто наличие одного тестового класса для каждого класса показалось, что он не сможет протестировать почти достаточно ситуаций, не становясь подавляющим, чтобы иметь весь этот тестовый код внутри одного тестового класса. Теперь у меня другая перспектива. Даже если бы я был прав, это огромный демпфер для других программистов и я, желая писать и поддерживать тесты. Теперь я экспериментирую с тем, чтобы заставить себя тестировать один класс тестов на класс. Если я испытываю слишком много вещей для тестирования в одном тестовом классе, я экспериментирую с тем, что это указывает на то, что тестируемый класс делает слишком много и должен быть разбит на несколько классов. Для устранения дублирования я стараюсь как можно больше придерживаться более простых абстракций, что позволяет всем существовать в одном читаемом классе тестов.