Intereting Posts
Где хранить ключ шифрования при использовании AES-шифрования с помощью PHP? Моя ошибка SQL: попытка подключения не удалась, потому что связанная сторона неправильно ответила PHP MySQL Поиск и заказ по релевантности Продукт :: getProductsProperties (): 'id_image' возвращает 'en_default', а не изображение Является ли плохая практика для модели называть себя внутри себя? Объекты PHP DOMNode и nodeValue Получить последний элемент массива без изменения массива в PHP? Каков правильный способ установки переменных ENV в Laravel 5? Невозможно отправить уведомление группе с помощью кнопки уведомления, даже если это возможно через regId Получение timestamp unix в миллисекундах в PHP5 и ActionScript3 PHP: имя oci_bind_by_name и timestamp приводит к «ORA-01461: может привязывать значение LONG только для вставки в столбцы LONG» PHP preg_match для поиска и поиска динамического URL-адреса из HTML-страниц Получайте количество будних дней в данном месяце Неустранимая ошибка с fetch_assoc внутри функции Как использовать прокси-сервер SOCKS 5 с cURL?

Организация тестов PHPUnit в пространствах имен

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

Рассмотрим образец класса, например \SomeFramework\Utilities\AwesomeClass :

  • Подход 1: Поместите каждый класс TestCase в то же пространство имен, что и закрытый класс.

     \SomeFramework\Utilities\AwesomeClassTest 
    • преимущества
      • В соответствии с традиционным подходом к написанию тестов PHPUnit.
    • Недостатки
      • Меньшая гибкость.
      • Кажется, нарушает принцип использования пространств имен – несвязанные тесты сгруппированы в одно и то же пространство имен.
  • Подход 2: Поместите каждую TestCase в пространство имен, названное в честь класса.

     \SomeFramework\Utilities\AwesomeClass\Test 
    • преимущества
      • Предоставляет очень простой / очевидный способ группировать несколько связанных классов TestCase вместе, например, для разных наборов тестов.
    • Недостатки
      • Может привести к более глубокой, более сложной иерархии.

Мое предложенное решение и рассуждения позади него:

Расположение папок:

 . ├── src │  ├── bar │  │  └── BarAwesomeClass.php │  └── foo │  └── FooAwesomeClass.php └── tests ├── helpers │  └── ProjectBaseTestClassWithHelperMethods.php ├── integration │  ├── BarModuleTest.php │  └── FooModuleTest.php └── unit ├── bar │  └── BarAwesomeClassTest.php └── foo └── FooAwesomeClassTest.php 

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

Папка integration/ содержит тесты, которые охватывают более классы и проверяют «большие» части системы. У вас их не так много, но нет сопоставления 1: 1 для производственных классов.

Папка unit/ folder отображает 1: 1 в src/ . Поэтому для каждого производственного класса существует один класс, который содержит все модульные тесты для этого класса.

Пространства имен

Подход 1: Поместите каждый класс TestCase в то же пространство имен, что и закрытый класс.

Этот подход к папке должен решить один из ваших недостатков с помощью подхода 1 . Вы по-прежнему получаете гибкость, чтобы иметь больше тестов, чем может показаться однозначное сопоставление 1: 1, но все упорядочено и на месте.

Кажется, нарушает принцип использования пространств имен – несвязанные тесты сгруппированы в одно и то же пространство имен.

Если тесты считают «несвязанными», возможно, производственный код имеет такую ​​же проблему?

Это правда, что тесты не зависят друг от друга, но они могут использовать свои «близкие» классы как mocks или использовать реальные в случае DTO или Value Objects. Поэтому я бы сказал, что есть соединение.

Подход 2: Поместите каждую TestCase в пространство имен, названное в честь класса.

Есть несколько проектов, которые это делают, но обычно они структурируют его несколько иначе:

Это не \SomeFramework\Utilities\AwesomeClass\Test , но \SomeFramework\Tests\Utilities\AwesomeClassTest и они все еще сохраняют отображение 1: 1, но добавили дополнительное пространство имен тестов.

Дополнительное пространство имен тестов

Мой личный подход заключается в том, что мне не нравится иметь отдельные пространства имен тестов, и я попытаюсь найти пару аргументов и против этого выбора:

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

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

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

Различия довольно незначительны (обычно это несколько «использования» или полностью квалифицированных путей)

Когда мы получим возможность сказать $this->getMock(AwesomeClass::CLASS) в PHP 5.5 вместо $this->getMock('\SomeFramework\Utilities\AwesomeClass') каждый макет потребует использования инструкции.

Для меня использование в модуле более ценно для большинства классов

Загрязнение пространства имен «Производство»

Когда вы скажете new \SomeFramework\Utilities\A автозаполнение может показать вам AwesomeClass и AwesomeClassTest и некоторые люди этого не хотят. Для внешнего использования или при отправке вашего источника, который не является проблемой, поскольку тесты не отправляются, но это может быть что-то, что нужно учитывать.

Существует третий вариант, который я использую, и который подходит для автозагрузки композитора: Вставьте Test пространство имен после первого шага в иерархии. В вашем случае это пространство имен \SomeFramework\Tests\Utilities\ и ваш класс будет \SomeFramework\Tests\Utilities\AwesomeClassTest .

Затем вы можете поставить тесты вместе с другими классами в \SomeFramework\Test или поместить их в отдельный каталог. Ваша информация об автозагрузке для composer.json может выглядеть так:

 { "autoload": { "psr-0": { "SomeFramework\\": "src/", } }, "autoload-dev": { "psr-0": { "SomeFramework\\Tests\\": "tests/" } } } 

Преимуществами третьего подхода являются:

  • Разделение тестов и производственный код
  • Аналогичные иерархии папок для тестов и производственных классов
  • Легкая автозагрузка

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

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

Одним из главных недостатков второго метода является то, что каждое имя тестового случая является Test который будет иметь несколько последствий:

  • Несколько открытых тестовых окон будут иметь одно и то же имя.
  • Функция IDE открытого типа по имени (CTRL-O в NetBeans) будет бесполезной для тестов.
  • Вы также можете выйти из командной строки ярлыка «перейти к тестированию» (CTRL-SHIFT-T в NetBeans).