我目前要从头开始使用phpunit测试项目.所以我正在研究一些项目(比如Zend),看看他们是如何做的以及他们如何组织他们的测试.
大多数事情都很清楚,只有我遇到的一些问题是如何正确组织测试套件.Zend有一个AllTests.php,从中加载其他测试套件.
艰难地查看它正在使用的类PHPUnit_Framework_TestSuite来创建一个套件对象然后添加其他套件,但如果我查看PHPUnit文档在3.4之后的PHPUnit版本中组织测试,那么只有XML或FileHierarchy的描述.使用类来组织测试的那个被删除了.
我没有发现任何不推荐使用此方法的内容,以及像Zend这样的项目仍在使用它.
但是如果它被弃用,我怎么能用xml配置在相同的结构中组织测试?执行所有测试都没有问题,但如果我只想执行一些测试,我将如何组织测试(在xml中).也许创建几个xmls,我只指定要运行的几个测试/测试套件?
因此,如果我只想测试应用程序的module1和module2,我是否每个都有一个额外的xml,并且仅为那些模块(模块使用的类)定义测试套件.还有一个为所有测试定义测试套件的?
或者@group,在特定测试中使用注释将它们标记为module1或module2 会更好吗?
提前感谢您指出一些最佳做法.
edo*_*ian 106
我将首先链接到手册,然后进入我在现场看到和听到的内容.
我推荐的方法是将文件系统与xml配置相结合.
tests/
\ unit/
| - module1
| - module2
- integration/
- functional/
Run Code Online (Sandbox Code Playgroud)
有phpunit.xml一个简单的:
<testsuites>
<testsuite name="My whole project">
<directory>tests</directory>
</testsuite>
</testsuites>
Run Code Online (Sandbox Code Playgroud)
如果你愿意,你可以拆分测试套件,但这是项目选择的项目.
phpunit然后运行将执行所有测试,并且运行phpunit tests/unit/module1将运行module1的所有测试.
这里最常用的方法是source/在tests/unit/文件夹结构中镜像目录结构.
无论如何,每个ProductionClass都有一个TestClass,所以这是我书中的一个好方法.
如果你在一个文件中有多个测试类,那么它无论如何都不会起作用,所以要避免这个陷阱.
它只是让编写测试更加冗长,因为你需要一个额外的use语句,所以我说testClass应该与生产类位于同一个命名空间中,但这不是PHPUnit强迫你做的事情.我刚刚发现它更容易没有任何缺点.
例如,phpunit --filter Factory在phpunit tests/unit/logger/执行与日志相关的所有操作时执行所有FactoryTests .
您可以使用@group标签来处理问题编号,故事或其他内容,但对于"模块",我会使用文件夹布局.
如果您想要创建多个xml文件,这将非常有用:
their phpunit.xmls因为它与使用测试启动新项目有关:
@covers标签(仅用于单元测试,始终涵盖所有非公共功能,始终使用封面标签.您的测试不需要任何类型的自动加载.PHPUnit将负责这一点.
使用该<phpunit bootstrap="file">属性指定测试引导程序.tests/bootstrap.php是一个不错的地方.在那里,您可以设置应用程序自动加载器等(或调用您的应用程序引导程序).
phpunit --filter或phpunit tests/unit/module1strictget go中的模式,永远不要将其关闭.基本目录结构:
我一直在尝试将测试代码放在被测试的代码旁边,实际上是在同一个目录中,文件名与正在测试的代码文件略有不同。到目前为止,我喜欢这种方法。这个想法是您不必花费时间和精力来保持代码和测试代码之间的目录结构同步。因此,如果您更改代码所在目录的名称,那么您也不需要去查找并更改测试代码的目录名称。这也使您可以花更少的时间寻找与某些代码配套的测试代码,因为它就在它旁边。这甚至可以减少使用测试代码创建文件的麻烦,因为您不必先找到包含测试的目录,可能创建一个新目录以匹配您为其创建测试的目录,然后创建测试文件。您只需在那里创建测试文件。
这样做的一个巨大优势是它意味着其他员工(不是你,因为你永远不会这样做)将不太可能避免编写测试代码,因为它只是太多的工作。即使他们向现有类添加方法,他们也不太可能不想向现有测试代码添加测试,因为查找测试代码的摩擦很小。
一个缺点是这使得在没有伴随测试的情况下发布生产代码变得更加困难。尽管如果您使用严格的命名约定,它仍然是可能的。例如,我一直在使用 ClassName.php、ClassNameUnitTest.php 和 ClassNameIntegrationTest.php。当我想运行所有单元测试时,有一个套件可以查找以 UnitTest.php 结尾的文件。集成测试套件的工作方式类似。如果我愿意,我可以使用类似的技术来防止测试发布到生产中。
这种方法的另一个缺点是当您只是在寻找实际代码而不是测试代码时,需要花费更多的精力来区分两者。但我觉得这实际上是一件好事,因为它迫使我们感受到测试代码也是代码这一现实的痛苦,它增加了自己的维护成本,并且与其他任何东西一样是代码的重要组成部分,而不是只是某个地方的东西。
每节课一个测试课:
这对大多数程序员来说远非实验性的,但对我来说却是。我正在试验每个被测试的课程只有一个测试课程。过去,我为每个被测试的类都有一个完整的目录,然后在该目录中有几个类。每个测试类都以某种方式设置被测试的类,然后有一堆方法,每个方法都有不同的断言。但后来我开始注意到我将这些对象放入的某些条件与它从其他测试类进入的其他条件有共同之处。重复变得难以处理,所以我开始创建抽象来删除它。测试代码变得非常难以理解和维护。我意识到了这一点,但我找不到对我有意义的替代方案。每个类只有一个测试类似乎无法测试几乎足够的情况,而不会在一个测试类中包含所有测试代码而变得不堪重负。现在我对此有了不同的看法。即使我是对的,这也是其他程序员和我自己想要编写和维护测试的巨大障碍。现在我正在尝试强迫自己为每个正在测试的课程设置一个测试课程。如果我在一个测试类中遇到太多要测试的东西,我会尝试将此视为正在测试的类做得太多的迹象,应该分成多个类。为了消除重复,我试图尽可能地坚持更简单的抽象,以允许所有内容都存在于一个可读的测试类中。
更新
我仍然在使用并喜欢这种方法,但我发现了一种非常好的技术来减少测试代码的数量和重复的数量。在测试类本身中编写可重用的断言方法很重要,该方法被该类中的测试方法大量使用。如果我将它们视为内部 DSL(鲍勃叔叔提倡的东西,实际上他提倡实际制作内部 DSL),这有助于我提出正确类型的断言方法。有时,您可以通过接受一个字符串参数来进一步理解这个 DSL 概念(实际上是创建一个 DSL),该参数具有一个简单的值,该值指的是您尝试执行的测试类型。例如,有一次我创建了一个可重用的断言方法,它接受一个 $left、$comparesAs 和一个 $right 参数。$this->assertCmp('a', '<', 'b').
老实说,我怎么强调这一点都不为过,它是使编写测试具有可持续性的整个基础(您和其他程序员希望继续这样做)。这使得测试增加的价值可能超过它们带走的价值。关键不是你需要使用那种精确的技术,关键是你需要使用某种可重用的抽象,允许你编写简短易读的测试。看起来我似乎脱离了这个问题,但我真的不是。如果你不这样做,你最终会陷入需要为每个被测试的类创建多个测试类的陷阱,事情真的从那里开始崩溃。