上下文
我最近继承了一个程序良好的PHP应用程序(sarcasm(的开发和维护。该应用程序基于一个商业软件(我不会说出它的名字(,并且有一层定制(我们的(构建在它的上面
不幸的是,这个应用程序使用了大量的全局和单态(双关语(。我已经为我们覆盖的所有内容构建了测试用例。然而,很多事情都依赖于某种全球状态,这可能会导致种族状况和各种奇怪的事情。
随机测试
为了捕捉这些怪人中的大多数(我喜欢这样称呼它们(,我构建了一个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);
}
}
它基本上随机化测试顺序,以确保测试不依赖于可能正确也可能不正确的全局状态。
问题
当测试我的自定义装饰器时,问题出现了。我没有在手册、谷歌或堆栈溢出中找到任何地方如何加载它。
在分析代码时,我看到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开关就可以确保套件中的每个测试都能正常工作。