PHPUnit рекомендации по организации тестов


в настоящее время я собираюсь начать с нуля с помощью PHPUnit тесты для проекта. Поэтому я изучал некоторые проекты (например, Zend), чтобы увидеть, как они делают вещи и как они организуют свои тесты.

большинство вещей довольно ясно, единственное, что у меня есть некоторые проблемы с тем, как правильно организовать тестовые комплекты. У зенда есть все тесты.php, с которого загружаются другие наборы тестов.
Жесткий взгляд на класс, который он использует PHPUnit_Framework_TestSuite чтобы создать объект suite, а затем добавить другие комплекты к нему, но если я посмотрю в документах PHPUnit для организации тестов в версиях PHPUnit после 3.4, есть только описание для XML или FileHierarchy. Тот, который использовал классы для организации тестов, был удален.
Я не нашел ничего, что этот метод устарел, и такие проекты, как Zend, все еще используют его.

но если он устарел, как бы я мог организовать тесты в той же структуре с конфигурацией xml? Выполнение всех тестов не является проблемой, но как бы я организовал тесты (в xml), если бы я хотел выполнить только несколько тестов. Может быть, создание нескольких xmls, где я указываю только несколько тестов/наборов тестов для запуска?

поэтому, если бы я хотел тестировать только module1 и module2 приложения, у меня был бы дополнительный xml для каждого и определение наборов тестов только для тех модулей (классов, используемых модулем) в нем. А также определяет набор тестов для всех тестов?

или было бы лучше использовать @group аннотация на конкретные тесты, чтобы отметить их, чтобы быть для module1 или module2?

заранее спасибо за указание мне на некоторые лучшие практики.

2 59

2 ответа:

я начну с ссылки на руководство, а затем перейду к тому, что я видел и слышал в этой области.

организация наборов тестов phpunit

модуль / тестовая организация папок в файловой системе

мой рекомендуемый подход заключается в объединении файловой системы с конфигурацией xml.

tests/
 \ unit/
 | - module1
 | - module2
 - integration/
 - functional/

С phpunit.xml с простого:

<testsuites>
  <testsuite name="My whole project">
    <directory>tests</directory>
  </testsuite>
</testsuites>

вы можете разделить testsuites, если вы хотите, но это проект, чтобы выбор проекта.

под управлением phpunit затем выполнит все тесты и запуск phpunit tests/unit/module1 будет выполняться все тесты module1.

организация папки "unit"

наиболее распространенный подход здесь, чтобы отразить ваш source/ структура каталогов в папке tests/unit/ структура папок.

у вас есть один тестовый класс на ProductionClass в любом случае, так что это хороший подход в моей книге.

в организации

  • один класс на файл.

это не будет работать в любом случае, если у вас есть более одного тестового класса в одном файле, так что избегайте этой ловушки.

  • нет тестового пространства имен

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

выполнение только нескольких тестов

phpunit --filter Factory выполняет все FactoryTests в то время как phpunit tests/unit/logger/ выполняет все связанные с ведением журнала.

можно использовать @group теги для чего-то вроде номеров выпусков, историй или чего-то еще, но для "модулей" я бы использовал макет папки.

несколько xml-файлов

это может быть полезно для создания нескольких xml-файлов, если вы хотите иметь:

  • один без кода покрытие
  • один только для модульных тестов (но не для функциональных или интеграционных или длительных тестов)
  • другие распространенные случаи "фильтра"
  • PHPBB3 например делает это для their phpunit.xmls

покрытие кода для ваших тестов

как это связано с запуском нового проекта с тестами:

  • мое предложение использовать @covers теги как описано в моей блог (только для модульных тестов, всегда охватывают все общественные функции, всегда используйте теги.
  • не создавайте покрытие для ваших интеграционных тестов. Это дает вам ложное чувство безопасности.
  • всегда используйте белый список, чтобы включить весь свой производственный код, чтобы цифры не лгали вам!

автоматическая загрузка и загрузка ваших тестов

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

использовать <phpunit bootstrap="file"> атрибут для указания начальной загрузки теста. tests/bootstrap.php хорошее место, чтобы положить его. Там вы можете настроить приложение autoloader и так далее (или вызвать приложение bootstrap, если на то пошло).

резюме

  • используйте конфигурацию xml для почти всего
  • отдельные модульные и интеграционные тесты
  • папки модульного теста должны отражать папку приложений структура
  • для выполнения только специальных тестов используйте phpunit --filter или phpunit tests/unit/module1
  • использовать strict режим с самого начала и никогда не выключайте его.

примеры проектов, чтобы посмотреть на

Базовая Структура Каталога:

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

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

одним из недостатков является то, что это затрудняет выпуск вашего производственного кода без сопровождающих его тестов. Хотя если вы используйте строгие соглашения об именах, которые все еще могут быть возможны. Например, я использую ClassName.php, ClassNameUnitTest.php и ClassNameIntegrationTest.РНР. Когда я хочу запустить все модульные тесты, есть набор, который ищет файлы, заканчивающиеся на UnitTest.РНР. Набор интеграционных тестов работает аналогично. Если бы я захотел, я мог бы использовать аналогичную технику, чтобы предотвратить выпуск тестов в производство.

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

один тестовый класс В класс:

Это далеко не экспериментально для большинства программистов, но это для меня. Я экспериментирую только с одним тестовым классом для каждого тестируемого класса. В прошлом у меня был целый каталог для каждого тестируемого класса, а затем у меня было несколько классов внутри этого каталога. Каждый тестовый класс устанавливает класс, который тестируется в определенном способ, а затем было множество методов, каждый из которых сделал другое утверждение. Но затем я начал замечать, что некоторые условия, в которые я бы ввел эти объекты, имели общее с другими условиями, в которые он попал из других тестовых классов. Дублирование стало слишком много, чтобы справиться, поэтому я начал создавать абстракции для его удаления. Тестовый код стало очень трудно понять и поддерживать. Я понимал это, но не видел альтернативы, которая имела бы для меня смысл. Как раз иметь один класс теста в класс казался, что он не сможет протестировать почти достаточно ситуаций, не становясь подавляющим, чтобы иметь весь этот тестовый код внутри одного тестового класса. Теперь у меня другая точка зрения на это. Даже если я был прав, это огромный демпфер для других программистов и меня, желающих писать и поддерживать тесты. Теперь я экспериментирую с тем, чтобы заставить себя иметь один тестовый класс для каждого класса. Если я столкнусь со слишком многими вещами, чтобы проверить в этом одном тестовом классе, я экспериментирую с видением это указывает на то, что тестируемый класс делает слишком много и должен быть разбит на несколько классов. Для удаления дублирования я пытаюсь придерживаться более простых абстракций, насколько это возможно, что позволяет всему существовать в одном читаемом тестовом классе.