From ebc9c63558e61ea13e246e1458a41d72360eaa74 Mon Sep 17 00:00:00 2001 From: Gintautas Miselis Date: Fri, 28 Dec 2018 00:47:57 +0200 Subject: [PATCH] PhpUnit XML reporter Like Junit, but generates testsuite for each test file --- .travis.yml | 2 +- src/Log/PhpUnit.php | 116 ++++++++++++++++++++++++++++++++++++++++++++ src/Runner.php | 18 +++++-- 3 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 src/Log/PhpUnit.php diff --git a/.travis.yml b/.travis.yml index ea2057f..698be98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: php env: - CODECEPTION_VERSION: '2.4.x-dev' + CODECEPTION_VERSION: 'dev-phpunit-xml-reports' php: - 7.1 diff --git a/src/Log/PhpUnit.php b/src/Log/PhpUnit.php new file mode 100644 index 0000000..d0afe92 --- /dev/null +++ b/src/Log/PhpUnit.php @@ -0,0 +1,116 @@ +getFileName(); + } else { + $reflector = new \ReflectionClass($test); + $filename = $reflector->getFileName(); + } + + if ($filename !== $this->currentFile) { + if ($this->currentFile !== null) { + parent::endTestSuite(new TestSuite()); + } + + //initialize all values to avoid warnings + $this->testSuiteAssertions[self::FILE_LEVEL] = 0; + $this->testSuiteTests[self::FILE_LEVEL] = 0; + $this->testSuiteTimes[self::FILE_LEVEL] = 0; + $this->testSuiteErrors[self::FILE_LEVEL] = 0; + $this->testSuiteFailures[self::FILE_LEVEL] = 0; + $this->testSuiteSkipped[self::FILE_LEVEL] = 0; + + $this->testSuiteLevel = self::FILE_LEVEL; + + $this->currentFile = $filename; + $this->currentFileSuite = $this->document->createElement('testsuite'); + $this->currentFileSuite->setAttribute('file', $filename); + + $this->testSuites[self::SUITE_LEVEL]->appendChild($this->currentFileSuite); + $this->testSuites[self::FILE_LEVEL] = $this->currentFileSuite; + } + + if (!$test instanceof Reported) { + parent::startTest($test); + return; + } + + $this->currentTestCase = $this->document->createElement('testcase'); + + $isStrict = Configuration::config()['settings']['strict_xml']; + + foreach ($test->getReportFields() as $attr => $value) { + if ($isStrict and !in_array($attr, $this->strictAttributes)) { + continue; + } + $this->currentTestCase->setAttribute($attr, $value); + } + } + + public function endTest(\PHPUnit\Framework\Test $test, float $time):void + { + if ($this->currentTestCase !== null && $test instanceof Test) { + $numAssertions = $test->getNumAssertions(); + $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions; + + $this->currentTestCase->setAttribute( + 'assertions', + $numAssertions + ); + } + + if ($test instanceof TestCase) { + parent::endTest($test, $time); + return; + } + + // In PhpUnit 7.4.*, parent::endTest ignores tests that aren't instances of TestCase + // so I copied this code from PhpUnit 7.3.5 + + $this->currentTestCase->setAttribute( + 'time', + \sprintf('%F', $time) + ); + $this->testSuites[$this->testSuiteLevel]->appendChild( + $this->currentTestCase + ); + $this->testSuiteTests[$this->testSuiteLevel]++; + $this->testSuiteTimes[$this->testSuiteLevel] += $time; + $this->currentTestCase = null; + } + + /** + * Cleans the mess caused by test suite manipulation in startTest + */ + public function endTestSuite(TestSuite $suite): void + { + if ($suite->getName()) { + if ($this->currentFile) { + //close last file in the test suite + parent::endTestSuite(new TestSuite()); + $this->currentFile = null; + } + $this->testSuiteLevel = self::SUITE_LEVEL; + } + parent::endTestSuite($suite); + } +} diff --git a/src/Runner.php b/src/Runner.php index 8b8e847..e7bd548 100644 --- a/src/Runner.php +++ b/src/Runner.php @@ -10,11 +10,12 @@ class Runner extends \PHPUnit\TextUI\TestRunner public static $persistentListeners = []; protected $defaultListeners = [ - 'xml' => false, - 'html' => false, - 'tap' => false, - 'json' => false, - 'report' => false + 'xml' => false, + 'phpunit-xml' => false, + 'html' => false, + 'tap' => false, + 'json' => false, + 'report' => false ]; protected $config = []; @@ -156,6 +157,13 @@ protected function applyReporters(\PHPUnit\Framework\TestResult $result, array $ [$this->absolutePath($arguments['xml']), (bool)$arguments['log_incomplete_skipped']] ); } + if ($arguments['phpunit-xml']) { + codecept_debug('Printing PHPUNIT report into ' . $arguments['phpunit-xml']); + self::$persistentListeners[] = $this->instantiateReporter( + 'phpunit-xml', + [$this->absolutePath($arguments['phpunit-xml']), (bool)$arguments['log_incomplete_skipped']] + ); + } if ($arguments['tap']) { codecept_debug('Printing TAP report into ' . $arguments['tap']); self::$persistentListeners[] = $this->instantiateReporter('tap', [$this->absolutePath($arguments['tap'])]);