这个问题:Run PHPUnit Tests in Certain Order有一个我同意的接受答案,但设计问题是PHP和PHPUnit。
我正在测试的项目使用ZF2和Doctrine。 AbstractHttpControllerTestCase有一个方法“dispatch”,它实例化ZF2应用程序并完成创建Response对象的所有步骤。这些测试使用@covers注释,以确保在测试期间运行请求不会涵盖其他方法。这些请求可能涉及调用使用各种服务的视图助手的视图脚本,因此模拟在给定请求期间使用的所有服务变得不可行(对于每个测试,此代码复制和维护将变得乏味。)
PHPUnit能够在一个单独的进程中运行测试,它通过分配一个新的PHP实例并提供它编译的代码模板(奇怪的东西)来实现。然后它将包含get_included_files()列出的所有文件,其中包括曾经击中自动加载器的所有内容。即使禁用了preserveGlobalState,它仍将包含新流程中所有先前测试所触及的所有内容。
一些依赖项(通过composer安装)使用静态方法,标记为final的类或两者。静态方法可以通过PHPUnit进行模拟,最终的类必须使用Mockery重载,因为PHPUnit会使得拒绝创建最终类的模拟对象。重载类和函数(使用命名空间技巧)必须在单独的进程中完成,以免影响后续测试。到目前为止,非常好。
输入一个测试,该测试重载依赖项以设置对静态方法的期望(在可能或可能不标记为final的类上),或者设置对尚未实例化的对象的期望。这只有在以前的测试都没有触及类重载和设置期望时才会起作用,或者它会因“无法重新声明类”错误而失败。 PHPUnit试图提供帮助,包括在子进程中重新创建测试环境的所有内容,但结果破坏了测试用例。
因此,用例如标记测试是非常有用的。 “@group isolated”并且在任何其他测试之前运行这些测试而不必两次调用PHPUnit(除了它的不便之外,它会破坏覆盖率分析)。
或者,如果有一种方法可以覆盖PHP 5.5中已经存在的类,那么将允许受损的测试用例修复其前提条件。但这可能不会发生(在任何情况下,runkit都不是一个可接受的答案)。