Ответ 1
Мое предложенное решение и рассуждения позади него:
Макет папки:
.
├── 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/
отображает 1:1 в src/
. Поэтому для каждого производственного класса существует один класс, содержащий все тесты unit для этого класса.
Пространство имен
Подход 1: Поместите каждый класс TestCase в то же пространство имен, что и класс.
Этот подход к папке должен решить один из ваших недостатков: Подход 1. Вы по-прежнему получаете гибкость, чтобы иметь больше тестов, чем может показаться однозначное сопоставление 1:1, но все упорядочено и находится на месте.
Кажется, нарушает принцип использования пространств имен - несвязанные тесты сгруппированы в одно и то же пространство имен.
Если тесты кажутся "несвязанными", возможно, производственный код имеет такую же проблему?
Верно, что тесты не зависят друг от друга, но они могут использовать свои "близкие" классы как mocks или использовать реальные в случае DTO или Value Objects. Поэтому я бы сказал, что есть соединение.
Подход 2: Поместите каждую TestCase в пространство имен, названное после класса.
Есть несколько проектов, которые это делают, но обычно они структурируют его несколько иначе:
Это не \SomeFramework\Utilities\AwesomeClass\Test
, но \SomeFramework\Tests\Utilities\AwesomeClassTest
, и они все еще сохраняют отображение 1:1, но с добавлением дополнительного пространства имен.
Экспериментальное пространство имен
Мой личный подход заключается в том, что мне не нравится иметь отдельные тестовые пространства имен, и я попытаюсь найти пару аргументов и против этого выбора:
Тесты должны служить документацией о том, как использовать класс
Когда настоящий класс находится в другом пространстве имен, тесты показывают, как использовать этот класс вне его собственного модуля.
Когда настоящий класс находится в одном пространстве имен, тесты показывают, как использовать этот класс изнутри этого модуля.
Различия довольно незначительные (обычно это несколько инструкций "use" или полностью квалифицированных путей)
Когда мы получим возможность сказать $this->getMock(AwesomeClass::CLASS)
в PHP 5.5 вместо $this->getMock('\SomeFramework\Utilities\AwesomeClass')
, каждый макет потребует использования оператора.
Для меня использование в модуле более ценно для большинства классов
Загрязнение пространства имен "Производство"
Когда вы скажете new \SomeFramework\Utilities\A
, автозаполнение может показать вам AwesomeClass
и AwesomeClassTest
, а некоторые люди этого не хотят. Для внешнего использования или при отправке источника, который не является проблемой, поскольку тесты не отправляются, но это может быть что-то, что нужно учитывать.