我提出的解决方案及其背后的原因:
文件夹布局:
.
├── 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/
. 因此,对于每个生产类,都有一个类包含该类的所有单元测试。
命名空间
方法 1:将每个 TestCase 类放入与被覆盖类相同的命名空间中。
这种文件夹方法应该可以解决您使用方法 1的一个缺点。您仍然可以灵活地进行比纯 1:1 映射所能提供的更多测试,但一切都已安排妥当。
似乎打破了使用命名空间背后的原则——不相关的测试被分组到同一个命名空间中。
如果测试感觉“不相关”,可能生产代码有同样的问题?
确实,这些测试并不相互依赖,但它们可能会使用它们的“关闭”类作为模拟,或者在 DTO 或值对象的情况下使用真实的类。所以我会说有联系。
方法 2:将每个 TestCase 放在以覆盖类命名的命名空间中。
有几个项目可以做到这一点,但通常它们的结构略有不同:
不是\SomeFramework\Utilities\AwesomeClass\Test
,但\SomeFramework\Tests\Utilities\AwesomeClassTest
他们仍然保持 1:1 映射,但添加了额外的测试命名空间。
额外的测试命名空间
我个人的看法是,我不喜欢有单独的测试命名空间,我会尝试找到一些支持和反对该选择的论据:
测试应该作为如何使用类的文档
当真正的类在另一个命名空间中时,测试显示如何在它自己的模块之外使用该类。
当真正的类在同一个命名空间中时,测试显示了如何从该模块内部使用该类。
差异很小(通常是几个“使用”语句或完全限定的路径)
当我们有可能$this->getMock(AwesomeClass::CLASS)
在 PHP 5.5 中说而不是$this->getMock('\SomeFramework\Utilities\AwesomeClass')
每个 mock 都需要一个 use 语句。
对我来说,模块内的使用对大多数类来说更有价值
污染“生产”命名空间
当您说new \SomeFramework\Utilities\A
自动完成可能会向您展示时AwesomeClass
,AwesomeClassTest
有些人不希望这样。对于外部使用,或者在运送您的源代码时,这当然不是问题,因为测试没有运送,但可能需要考虑。