问题描述
我看到两个用于将PHPUnit单元测试组织到名称空间层次结构中的选项.这两种方法的优点/缺点是什么?有没有我没有考虑过的明显缺陷可以使一个明显更好的选择?
I see two options for organizing PHPUnit unit tests into a namespace hierarchy. What are the advantages/disadvantages to these two approaches? Are there any obvious flaws I haven't considered that would make one the obvious better choice?
考虑一个类似于\SomeFramework\Utilities\AwesomeClass
的示例类:
Consider a sample class like \SomeFramework\Utilities\AwesomeClass
:
-
方法1::将每个TestCase类放入与所覆盖类相同的名称空间中.
Approach 1: Place each TestCase class into the same namespace as the covered class.
\SomeFramework\Utilities\AwesomeClassTest
- 优势
- 与编写PHPUnit测试的传统方法一致.
- Advantages
- Consistent with the traditional approach to writing PHPUnit tests.
- 缺乏灵活性.
- 似乎打破了使用命名空间的原则-无关的测试被分组到同一命名空间中.
- Less flexibility.
- Seems to break the principle behind using namespaces - unrelated tests are grouped into the same namespace.
方法2:将每个TestCase放置在以所覆盖类命名的命名空间中.
Approach 2: Place each TestCase in a namespace named after the covered class.
\SomeFramework\Utilities\AwesomeClass\Test
- 优势
- 提供了一种非常简单/明显的方法来将多个相关的TestCase类分组在一起,例如针对不同的测试套件.
- Advantages
- Provides a very easy/obvious way to group multiple related TestCase classes together, say for different test suites.
- 可能会导致更深层次,更复杂的层次结构.
推荐答案
我提出的解决方案及其背后的原因:
My proposed solution and the reasoning behind it:
. ├── 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,其中可能包含项目特定的帮助器方法,以及几个易于重用的存根类,因此您不需要那么多的模拟.The
helpers/
folder contains classes that are not tests but are only used in a testing context. Usually that folder contains a BaseTestClass maybe containing project specific helper methods and a couple of easy to reuse stub classes so you don't need as many mocks.integration/
文件夹包含跨更多类的测试,并且测试系统的更大"部分.它们数量不多,但是没有1:1映射到生产类.The
integration/
folder contains tests that span over more classes and test "bigger" parts of the system. You don't have as many of them but there is no 1:1 mapping to production classes.unit/
文件夹将1:1映射到src/
.因此,对于每个生产类,都有一个类包含该类的所有单元测试.The
unit/
folder maps 1:1 to thesrc/
. So for every production class there is one class that contains all the unit tests for that class.此文件夹方法应使用方法1 解决您的缺点之一.您仍然可以拥有比纯1:1映射所能提供的更多测试的灵活性,但是一切都是有序的.
This folder approach should solve one of your disadvantages with Approach 1. You still get the flexibility to have more tests than a pure 1:1 mapping could give you but everything is ordered and in place.
如果测试感到无关",也许生产代码也有同样的问题?
If the tests feel "unrelated" maybe the production code has the same issue?
的确,测试之间并不相互依赖,但是在DTO或Value Objects的情况下,它们可能将其"close"类用作模拟或使用真实的模拟.所以我想说有联系.
It's true that the tests don't depend on one another but they might use their "close" classes as mocks or use the real ones in case of DTOs or Value Objects. So i'd say that there is a connection.
有几个项目可以做到这一点,但是通常它们的结构有些不同:
There are a couple of projects that do that but usually they structure it a little differently:
不是
\SomeFramework\Utilities\AwesomeClass\Test
,而是\SomeFramework\Tests\Utilities\AwesomeClassTest
,它们仍然保留1:1映射,但添加了额外的测试名称空间.It's not
\SomeFramework\Utilities\AwesomeClass\Test
, but\SomeFramework\Tests\Utilities\AwesomeClassTest
and they still keep the 1:1 mapping, but with the extra test namespace added.我个人认为我不喜欢拥有单独的测试名称空间,我将尝试为该选择和反对选择一对参数:
My personal take is that I don't like having separate test namespaces and I'll try to find a couple for arguments for and against that choice:
当真实类位于另一个命名空间中时,测试将显示如何在其自己的模块之外使用该类.
When the real class is in another namespace, the tests show how to use that class outside of its own module.
当真实类位于相同的名称空间中时,测试将显示如何在该模块内部使用该类.
When the real class is in the same namespace, the tests show how to use that class from inside that module.
差异很小(通常是几个使用"语句或完全限定的路径)
The differences are quite minor (usually a couple of "use" statements or fully-qualified paths)
当我们有可能在PHP 5.5中说
$this->getMock(AwesomeClass::CLASS)
而不是$this->getMock('\SomeFramework\Utilities\AwesomeClass')
时,每个模拟都需要一个use语句.When we get the possibility to say
$this->getMock(AwesomeClass::CLASS)
in PHP 5.5 instead of$this->getMock('\SomeFramework\Utilities\AwesomeClass')
every mock will require a use statement.对我来说,模块中的用法对于大多数类而言更有价值
For me the usage within the module is more valuable for most classes
当您说
new \SomeFramework\Utilities\A
时,自动完成功能可能会显示AwesomeClass
和AwesomeClassTest
,有些人不想要.对于外部使用,或在运输您的源时,这当然不是问题,因为测试未交付,但这可能是要考虑的问题.When you say
new \SomeFramework\Utilities\A
the auto completion might show youAwesomeClass
andAwesomeClassTest
and some people don't want that. For external use, or when shipping your source that isn't a problem of course since the tests don't get shipped but it might be something to consider.这篇关于在命名空间中组织PHPUnit测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!