问题
You may use --stop-on-failure
flag to break the unit testing when one of the tests fails.
Is there any way quick way to tell PHPUnit to re-run this failed test, instead providing the full path manually?
回答1:
Take a look at the --filter
cli option. You can find an example in the organisation docs and in the CLI Docs.
--filter
Only runs tests whose name matches the given pattern. The pattern can be either the name of a single test or a regular expression that matches multiple test names.
Assume your run phpunit Tests/
and Tests/Stuff/ThatOneTestClassAgain::testThisWorks
fails:
your options are:
phpunit --filter ThatOneTestClassAgain
and
phpunit --filter testThisWorks
or most other strings that somehow make sense
回答2:
Since PhpUnit 7.3, you can cache the results of your tests, then order your tests by defects.
In phpunit.xml, enable cacheResults
:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit cacheResult="true"
...>
If you don't want to edit your phpunit.xml, you could also run your tests with the --cache-result
flag.
When caching results, PhpUnit will create a .phpunit.result.cache
file after running tests (make sure to add this file to your (global) gitignore file).
You can run your tests like this to run previously failed tests first:
phpunit --order-by=defects --stop-on-failure
回答3:
The way I've found to implement it is fairly easy, but requires logging to be implemented. You setup phpunit to log to a json file. Then you alter the phpunit command to something similar to:
cd /home/vagrant/tests && php -d auto_prepend_file=./tests-prepend.php /usr/local/bin/phpunit
What this does is auto_prepend a php file before the execution of phpunit. This way we can capture $argsv and supply the required filter command automatically to phpunit.
tests-prepend.php (make sure to amend the file pathway of the json log)
<?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;
}
}
}
来源:https://stackoverflow.com/questions/7119886/re-run-last-failed-test-in-phpunit