重新运行PHPUnit中上次失败的测试

18
你可以使用--stop-on-failure标志,在单元测试中当一个测试失败时中断执行。
是否有一种快速的方式告诉PHPUnit重新运行此失败的测试,而不是手动提供完整路径?
3个回答

35

自 PHPUnit 7.3 开始, 您可以缓存测试结果,然后按照缺陷对测试进行排序。

在 phpunit.xml 中启用 cacheResults

<?xml version="1.0" encoding="UTF-8"?>
<phpunit cacheResult="true"
         ...>

如果您不想编辑phpunit.xml,也可以使用--cache-result标志运行测试。
在缓存结果时,PHPUnit将在运行测试后创建.phpunit.result.cache文件。请确保将此文件添加到全局gitignore文件中。
您可以像这样运行测试以首先运行以前失败的测试:
phpunit --order-by=defects --stop-on-failure

3
PHPUnit 9.*中默认情况下cacheResult为true。 - Robin van Baalen
1
所有失败的测试都成功后,这个过程会停止吗?这只会让你在上一次运行中失败的地方得到“快速反馈”。但是如果你修复了所有问题,它最终仍然会运行所有的测试,不是吗? - Tomáš Fejfar

12
请查看--filter cli选项。 您可以在组织文档cli文档中找到示例。

--filter

只运行其名称与给定模式匹配的测试。该模式可以是单个测试名称或可匹配多个测试名称的正则表达式。

假设您运行phpunit Tests/并且Tests/Stuff/ThatOneTestClassAgain::testThisWorks失败了:
您有以下选择: phpunit --filter ThatOneTestClassAgainphpunit --filter testThisWorks 或任何其他一些合理的字符串。

3
如果您已经为测试设置了 phpunit.xml 配置文件,我创建了一个简短的 bash 脚本,它将使用 phpunit 的日志记录来填充 --filter 选项,以包含上一次测试运行中存在失败测试的类。请查看此 gist 顶部的注释,使用这个脚本。 - bksunday

2

我发现实现它的方法相当简单,但需要实现日志记录。您可以设置phpunit将日志记录到json文件中。然后您需要修改phpunit命令,使其类似于:

cd /home/vagrant/tests && php -d auto_prepend_file=./tests-prepend.php /usr/local/bin/phpunit

这个功能是自动在执行phpunit之前,预先添加一个php文件。这样我们就可以捕获$argsv并自动提供所需的过滤命令给phpunit。 tests-prepend.php (请确保修改json日志文件的路径)
<?php

global $argv, $argc;
if(empty($argv) === false) {
    // are we re-running?
    $has_rerun = false;
    foreach ($argv as $key => $value) {
        if($value === '--rerun-failures') {
            $has_rerun = true;
            unset($argv[$key]);
            break;
        }
    }
    if($has_rerun === true) {
        // validate the path exists and if so then capture the json data.
        $path = realpath(dirname(__FILE__).'/../logs/report.json');
        if(is_file($path) === true) {
            // special consideration taken here as phpunit does not store the report as a json array.
            $data = json_decode('['.str_replace('}{'.PHP_EOL, '},{'.PHP_EOL, file_get_contents($path).']'), true);
            $failed = array();
            // capture the failures as well as errors but taking care not to capture skipped tests.
            foreach ($data as $event) {
                if($event['event'] === 'test') {
                    if($event['status'] === 'fail') {
                        $failed[] = array($event['test'], 'failed');
                    }
                    elseif($event['status'] === 'error' && $event['trace'][0]['function'] !== 'markTestIncomplete') {
                        $failed[] = array($event['test'], 'error\'d');
                    }
                }
            }
            if(empty($failed) === true) {
                echo 'There are no failed tests to re-run.'.PHP_EOL.PHP_EOL;
                exit;
            }
            else{
                echo '--------------------------------------------------------------------'.PHP_EOL;
                echo 'Re-running the following tests: '.PHP_EOL;
                foreach ($failed as $key => $test_data) {
                    echo ' - '.$test_data[0].' ('.$test_data[1].')'.PHP_EOL;
                    // important to escapre the namespace backslashes.
                    $failed[$key] = addslashes($test_data[0]);
                }
                echo '--------------------------------------------------------------------'.PHP_EOL.PHP_EOL;
            }
            $argv[] = '--filter';
            $argv[] = '/('.implode('|', $failed).')/';
            // important to update the globals in every location.
            $_SERVER['argv'] = $GLOBALS['_SERVER']['argv'] = $GLOBALS['argv'] = $argv = array_values($argv);
            $_SERVER['argc'] = $GLOBALS['_SERVER']['argc'] = $GLOBALS['argc'] = $argc = count($argv);
        }
        else{
            echo 'The last run report log at '.$path.' does not exist so it is not possible to re-run the failed tests. Please re-run the test suite without the --rerun-failures command.'.PHP_EOL.PHP_EOL;
            exit;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接