ParaTest
ParaTest 的目标是支持 PHPUnit 的并行测试。只要你有编写良好的 PHPUnit 测试,你就可以将 paratest
添加到你的项目中,无需额外的引导或配置即可开始使用!
优点:
- 零配置。安装后,运行
vendor/bin/paratest
按测试用例并行化,或运行vendor/bin/paratest --functional
按测试并行化。就是这么简单! - 代码覆盖率报告合并。在 N 个并行进程中运行你的测试,所有代码覆盖率输出将被合并成一份报告。
安装
使用 composer 运行以下命令进行安装:
composer require --dev brianium/paratest
版本
仅支持 PHPUnit 的最新版本,因此只有 ParaTest 的最新版本会得到积极维护。
这是由于以下原因:
- 为了减少 bug、代码重复和与 PHPUnit 的不兼容性,从版本 5 开始,ParaTest 严重依赖 PHPUnit 的
@internal
类 - PHP 和 PHPUnit 最近的快速发展增加了太多维护负担,我们只能负担得起最新版本以保持最新
使用
安装后,可以在 vendor/bin/paratest
找到二进制文件。使用 --help
选项运行它以查看可用选项的完整列表。
测试令牌
TEST_TOKEN
环境变量保证有一个与当前运行的每个其他测试不同的值。这对于例如为每个测试使用不同的数据库很有用:
if (getenv('TEST_TOKEN') !== false) { // 使用 ParaTest
$dbname = 'testdb_' . getenv('TEST_TOKEN');
} else {
$dbname = 'testdb';
}
还有一个 UNIQUE_TEST_TOKEN
环境变量,保证每次运行和每个进程都有一个唯一的值。
代码覆盖率
ParaTest 在执行测试套件之前始终会预热缓存。
PCOV
如果你已安装 pcov
,但需要仅在运行测试时启用它,你必须传递所需的 PHP 二进制选项:
php -d pcov.enabled=1 vendor/bin/paratest --passthru-php="'-d' 'pcov.enabled=1'"
xDebug
如果你已安装 xDebug
,通过环境变量激活它就足以让它在子进程中运行:
XDEBUG_MODE=coverage vendor/bin/paratest
所有测试的初始设置
由于 ParaTest 并行运行多个进程,每个进程都有自己的 PHP 解释器实例,用于为每个测试执行一次初始化步骤的技术与 PHPUnit 不同。以下模式不会按预期工作 - 只运行一次初始化 - 而是每个进程运行一次初始化:
private static bool $initialized = false;
public function setUp(): void
{
if (! self::$initialized) {
self::initialize();
self::$initialized = true;
}
}
这是因为静态变量在单个进程执行期间持续存在。在并行测试中,每个进程都有一个单独的 $initialized
实例。你可以使用以下模式来确保初始化在整个测试调用中只运行一次:
static bool $initialized = false;
public function setUp(): void
{
if (! self::$initialized) {
// 我们利用文件系统作为共享可变状态来协调进程之间的通信
touch('/tmp/test-initialization-lock-file');
$lockFile = fopen('/tmp/test-initialization-lock-file', 'r');
// 尝试获取独占锁 - 第一个进程获胜
if (flock($lockFile, LOCK_EX | LOCK_NB)) {
// 由于我们是唯一拥有独占锁的进程,我们运行初始化
self::initialize();
} else {
// 如果没有可用的独占锁,则阻塞直到第一个进程完成初始化
flock($lockFile, LOCK_SH);
}
self::$initialized = true;
}
}
故障排除
如果你在运行 paratest
时遇到问题,请尝试通过 --verbose --debug
启用调试输出以获取有关问题的更多信息。
当子进程失败时,输出中会给出原始命令,然后可以将其复制粘贴到终端中运行和调试。所有内部命令都使用 --printer [...]\NullPhpunitPrinter
运行,这会静音原始 PHPUnit 输出:在调试运行期间,删除该选项以恢复输出并查看 PHPUnit 正在做什么。
注意事项
- 不支持常量、静态方法、静态变量以及其他测试类消耗的测试类公开的所有内容(包括反射)。这是由于当前
WrapperRunner
实现的限制以及 PHPUnit 搜索类的方式。解决方法是将共享代码放入非测试类中。
与 PHPStorm 集成
ParaTest 提供了一个专用的二进制文件来与 PHPStorm 配合使用;按照以下步骤在其中使用 ParaTest:
- 确保你已经在 PHPStorm 中配置了 PHPUnit:https://www.jetbrains.com/help/phpstorm/using-phpunit-framework.html#php_test_frameworks_phpunit_integrate
- 转到
运行
->编辑配置...
- 选择
添加新配置
,选择PHPUnit
类型并将其命名为ParaTest
- 在
命令行
->解释器选项
中添加./vendor/bin/paratest_for_phpstorm
- 你想传递给 ParaTest 的任何其他 ParaTest 选项都应放在
测试运行器
->测试运行器选项
部分
现在你应该在配置列表中有一个 ParaTest
运行。
它应该可以与 运行
覆盖层的 重新运行失败的测试
和 切换自动测试
按钮原生配合使用。
运行覆盖率
使用可用的覆盖率引擎之一的覆盖率必须已经在 PHPStorm 中配置,并且在顺序运行测试时能正常工作,以便辅助二进制文件能够正确处理代码覆盖率。
对贡献者:测试 ParaTest 本身
在创建拉取请求之前,请确保使用 make
命令运行所有必要的检查。