上下文
我最近继承了一个程序良好的 PHP 应用程序的开发和维护(讽刺)。该应用程序基于商业软件(我不会命名),并且有一个自定义层(我们的)构建在它之上。
不幸的是,此应用程序使用大量 全局变量和单例变量(双关语)。我已经为我们覆盖的所有内容构建了测试用例。然而,很多事情都依赖于某些全局状态,这可能会导致竞争条件和各种奇怪的事情。
随机化测试
为了捕捉这些奇怪的东西中的大部分(我喜欢这样调用它们),我构建了一个 PHPUnit TestDecorator
,[如手册][1]。这个:
class PHPUnit_Extensions_Randomizer extends PHPUnit_Extensions_TestDecorator
{
public function __construct(PHPUnit_Framework_Test $test)
{
$tests = $test->tests();
$shuffle = array();
foreach ($tests as $t) {
if ($t instanceof PHPUnit_Framework_TestSuite) {
$shuffle = array_merge($shuffle, $t->tests());
} else {
$shuffle[] = $t;
}
}
shuffle($shuffle);
$suite = new PHPUnit_Framework_TestSuite();
foreach ($shuffle as $t) $suite->addTest($t);
parent::__construct($suite);
}
}
它基本上随机化了测试顺序,以确保测试不依赖于可能正确或可能不正确的全局状态。
问题
问题出现在测试我的自定义装饰器的时候。我没有在手册、谷歌或 Stack Overflow 的任何地方找到如何加载它。
在分析代码时,我看到PHPUnit本身在TextUI_TestRunner::doRun()
方法中实例化了RepeatedTest
装饰器。我知道我可以子类化 TestRunner
,覆盖 doRun()
,安排创建我的装饰器,然后调用 parent::doRun()
以我的装饰器实例作为参数,覆盖 TextUI_Command
并创建一个新的 CLI 脚本来使用我的东西而不是内置的东西。
在我(重新)发明轮子之前,我只是想知道,是否可以在不对 TestRunner 进行子类化的情况下加载自定义装饰器?
谢谢。
最佳答案
对于当前的 PHPUnit 版本,大部分情况下都没有简单的方法插入您自己的代码。唯一提供可互换性的是 TestRunner,您描述的内容对我来说很有意义。
我不知道有任何其他方法可以提供测试装饰器或更改 phpunit 使用的大多数其他类。
即使如此,您想要更改测试执行顺序的方式似乎也行得通,但我不确定它洗牌的效果如何。
实现此目的的另一种方法可能更简单,是创建 PHPUnit_Framework_TestSuite
的子类。随机addTest
你的代码。
如果这不起作用,另一种选择是使用 xml 配置文件并从 <file>
构建测试套件。标签并在每次执行之前都有一些代码洗牌这些标签。 Afaik phpunit 不会以任何方式对它们进行排序,因此执行将是随机的
您是否正在查看其上的每个测试是否真的有效并希望找到相互依赖的测试?
或者您是否真的想看看当您执行大量不应按错误顺序更改任何内容的操作时是否会出现严重错误?
我问你是为了防止你没有考虑过 --process-isolation
然而。 (我假设你有,但问不会伤害你,可能会节省你一些时间和精力 :) )
当您使用一组新的全局变量运行每个测试时,您至少会发现所有测试的相互依赖性,而这只是一个 cli 开关,以确保您套件中的每个测试都能独立运行。
关于php - 扩展 PHPUnit : adding a decorator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8142920/