Merge branch 'junitResult'

This commit is contained in:
Dmitry Khomutov 2017-07-23 18:49:49 +07:00
commit 191dc6fc3d
No known key found for this signature in database
GPG key ID: 7EB36C9576F9ECB9
8 changed files with 660 additions and 324 deletions

View file

@ -7,7 +7,8 @@ use PHPCensor\Builder;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin\Option\PhpUnitOptions;
use PHPCensor\Plugin\Util\PhpUnitResult;
use PHPCensor\Plugin\Util\PhpUnitResultJson;
use PHPCensor\Plugin\Util\PhpUnitResultJunit;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
@ -79,18 +80,28 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
return false;
}
$cmd = $this->findBinary('phpunit');
// run without logging
$ret = null;
$lastLine = exec($cmd.' --log-json . --version');
if (false !== strpos($lastLine, '--log-json')) {
$logFormat = 'junit'; // --log-json is not supported
} else {
$logFormat = 'json';
}
$success = [];
// Run any directories
if (!empty($directories)) {
foreach ($directories as $directory) {
$success[] = $this->runDir($directory);
$success[] = $this->runConfig($directory, null, $logFormat);
}
} else {
// Run any config files
if (!empty($xmlConfigFiles)) {
foreach ($xmlConfigFiles as $configFile) {
$success[] = $this->runConfigFile($configFile);
$success[] = $this->runConfig($this->options->getTestsPath(), $configFile, $logFormat);
}
}
}
@ -99,60 +110,35 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
}
/**
* Run the PHPUnit tests in a specific directory or array of directories.
* Run the tests defined in a PHPUnit config file or in a specific directory.
*
* @param $directory
*
* @return bool|mixed
*/
protected function runDir($directory)
{
$options = clone $this->options;
$buildPath = $this->build->getBuildPath() . DIRECTORY_SEPARATOR;
// Save the results into a json file
$jsonFile = @tempnam($buildPath, 'jLog_');
$options->addArgument('log-json', $jsonFile);
// Removes any current configurations files
$options->removeArgument('configuration');
$arguments = $this->builder->interpolate($options->buildArgumentString());
$cmd = $this->findBinary('phpunit') . ' %s "%s"';
$success = $this->builder->executeCommand($cmd, $arguments, $directory);
$this->processResults($jsonFile);
return $success;
}
/**
* Run the tests defined in a PHPUnit config file.
*
* @param $configFile
* @param string $logFormat
*
* @return bool|mixed
*/
protected function runConfigFile($configFile)
protected function runConfig($directory, $configFile, $logFormat)
{
$options = clone $this->options;
$buildPath = $this->build->getBuildPath() . DIRECTORY_SEPARATOR;
$buildPath = $this->build->getBuildPath();
// Save the results into a json file
$jsonFile = @tempnam($buildPath, 'jLog_');
$options->addArgument('log-json', $jsonFile);
// Save the results into a log file
$logFile = @tempnam($buildPath, 'jLog_');
$options->addArgument('log-'.$logFormat, $logFile);
// Removes any current configurations files
$options->removeArgument('configuration');
// Only the add the configuration file been passed
$options->addArgument('configuration', $buildPath . $configFile);
if (null !== $configFile) {
// Only the add the configuration file been passed
$options->addArgument('configuration', $buildPath . $configFile);
}
$arguments = $this->builder->interpolate($options->buildArgumentString());
$cmd = $this->findBinary('phpunit') . ' %s %s';
$success = $this->builder->executeCommand($cmd, $arguments, $options->getTestsPath());
$success = $this->builder->executeCommand($cmd, $arguments, $directory);
$this->processResults($jsonFile);
$this->processResults($logFile, $logFormat);
return $success;
}
@ -160,14 +146,19 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
/**
* Saves the test results
*
* @param string $jsonFile
* @param string $logFile
* @param string $logFormat
*
* @throws \Exception If the failed to parse the JSON file
* @throws \Exception If failed to parse the log file
*/
protected function processResults($jsonFile)
protected function processResults($logFile, $logFormat)
{
if (file_exists($jsonFile)) {
$parser = new PhpUnitResult($jsonFile, $this->build->getBuildPath());
if (file_exists($logFile)) {
if ('json' === $logFormat) {
$parser = new PhpUnitResultJson($logFile, $this->build->getBuildPath());
} else {
$parser = new PhpUnitResultJunit($logFile, $this->build->getBuildPath());
}
$this->build->storeMeta('phpunit-data', $parser->parse()->getResults());
$this->build->storeMeta('phpunit-errors', $parser->getFailures());
@ -178,9 +169,9 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
$this->builder, 'php_unit', $error['message'], $severity, $error['file'], $error['line']
);
}
@unlink($jsonFile);
@unlink($logFile);
} else {
throw new \Exception('JSON output file does not exist: ' . $jsonFile);
throw new \Exception('log output file does not exist: ' . $logFile);
}
}
}

View file

@ -7,19 +7,17 @@ namespace PHPCensor\Plugin\Util;
*
* @author Pablo Tejada <pablo@ptejada.com>
*/
class PhpUnitResult
abstract class PhpUnitResult
{
const EVENT_TEST = 'test';
const EVENT_TEST_START = 'testStart';
const EVENT_SUITE_START = 'suiteStart';
const SEVERITY_PASS = 'success';
const SEVERITY_FAIL = 'fail';
const SEVERITY_ERROR = 'error';
const SEVERITY_SKIPPED = 'skipped';
const SEVERITY_WARN = self::SEVERITY_PASS;
const SEVERITY_RISKY = self::SEVERITY_PASS;
protected $options;
protected $arguments = [];
protected $outputFile;
protected $buildPath;
protected $results;
protected $failures = 0;
protected $errors = [];
@ -36,158 +34,48 @@ class PhpUnitResult
* @return $this
* @throws \Exception If fails to parse the output
*/
public function parse()
abstract public function parse();
abstract protected function getSeverity($testcase);
abstract protected function buildMessage($testcase);
abstract protected function buildTrace($testcase);
protected function getFileAndLine($testcase)
{
$rawResults = file_get_contents($this->outputFile);
$events = [];
if ($rawResults && $rawResults[0] == '{') {
$fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']';
$events = json_decode($fixedJson, true);
} elseif ($rawResults) {
$events = json_decode($rawResults, true);
}
// Reset the parsing variables
$this->results = [];
$this->errors = [];
$this->failures = 0;
if ($events) {
foreach ($events as $event) {
if (isset($event['event']) && $event['event'] == self::EVENT_TEST) {
$this->results[] = $this->parseEvent($event);
}
}
}
return $this;
return $testcase;
}
/**
* Parse a test event
*
* @param array $event
*
* @return string[]
*/
protected function parseEvent($event)
protected function getOutput($testcase)
{
list($pass, $severity) = $this->getStatus($event);
return $testcase['output'];
}
protected function parseTestcase($testcase)
{
$severity = $this->getSeverity($testcase);
$pass = isset(array_fill_keys([self::SEVERITY_PASS, self::SEVERITY_SKIPPED], true)[$severity]);
$data = [
'pass' => $pass,
'severity' => $severity,
'message' => $this->buildMessage($event),
'trace' => $pass ? [] : $this->buildTrace($event),
'output' => $event['output'],
'message' => $this->buildMessage($testcase),
'trace' => $pass ? [] : $this->buildTrace($testcase),
'output' => $this->getOutput($testcase),
];
if (!$pass) {
$this->failures++;
$this->addError($data, $event);
$info = $this->getFileAndLine($testcase);
$this->errors[] = [
'message' => $data['message'],
'severity' => $severity,
'file' => $info['file'],
'line' => $info['line'],
];
}
return $data;
}
/**
* Build the status of the event
*
* @param $event
*
* @return mixed[bool,string] - The pass and severity flags
* @throws \Exception
*/
protected function getStatus($event)
{
$status = $event['status'];
switch ($status) {
case 'fail':
$pass = false;
$severity = self::SEVERITY_FAIL;
break;
case 'error':
if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) {
$pass = true;
$severity = self::SEVERITY_SKIPPED;
} else {
$pass = false;
$severity = self::SEVERITY_ERROR;
}
break;
case 'pass':
$pass = true;
$severity = self::SEVERITY_PASS;
break;
case 'warning':
$pass = true;
$severity = self::SEVERITY_PASS;
break;
default:
throw new \Exception("Unexpected PHPUnit test status: {$status}");
break;
}
return [$pass, $severity];
}
/**
* Build the message string for an event
*
* @param array $event
*
* @return string
*/
protected function buildMessage($event)
{
$message = $event['test'];
if ($event['message']) {
$message .= PHP_EOL . $event ['message'];
}
return $message;
}
/**
* Build a string base trace of the failure
*
* @param array $event
*
* @return string[]
*/
protected function buildTrace($event)
{
$formattedTrace = [];
if (!empty($event['trace'])) {
foreach ($event['trace'] as $step){
$line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
$formattedTrace[] = $line;
}
}
return $formattedTrace;
}
/**
* Saves additional info for a failing test
*
* @param array $data
* @param array $event
*/
protected function addError($data, $event)
{
$firstTrace = end($event['trace']);
reset($event['trace']);
$this->errors[] = [
'message' => $data['message'],
'severity' => $data['severity'],
'file' => str_replace($this->buildPath, '', $firstTrace['file']),
'line' => $firstTrace['line'],
];
$this->results[] = $data;
}
/**

View file

@ -0,0 +1,145 @@
<?php
namespace PHPCensor\Plugin\Util;
/**
* Class PhpUnitResult parses the results for the PhpUnitV2 plugin
*
* @author Pablo Tejada <pablo@ptejada.com>
*/
class PhpUnitResultJson extends PhpUnitResult
{
const EVENT_TEST = 'test';
const EVENT_TEST_START = 'testStart';
const EVENT_SUITE_START = 'suiteStart';
protected $options;
protected $arguments = [];
/**
* Parse the results
*
* @return $this
* @throws \Exception If fails to parse the output
*/
public function parse()
{
$rawResults = file_get_contents($this->outputFile);
$events = [];
if ($rawResults && $rawResults[0] == '{') {
$fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']';
$events = json_decode($fixedJson, true);
} elseif ($rawResults) {
$events = json_decode($rawResults, true);
}
// Reset the parsing variables
$this->results = [];
$this->errors = [];
$this->failures = 0;
if ($events) {
foreach ($events as $event) {
if (isset($event['event']) && $event['event'] == self::EVENT_TEST) {
$this->parseTestcase($event);
}
}
}
return $this;
}
/**
* Build the severity of the event
*
* @param $event
*
* @return string The severity flags
* @throws \Exception
*/
protected function getSeverity($event)
{
$status = $event['status'];
switch ($status) {
case 'fail':
$severity = self::SEVERITY_FAIL;
break;
case 'error':
if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) {
$severity = self::SEVERITY_SKIPPED;
} else {
$severity = self::SEVERITY_ERROR;
}
break;
case 'pass':
$severity = self::SEVERITY_PASS;
break;
case 'warning':
$severity = self::SEVERITY_PASS;
break;
default:
throw new \Exception("Unexpected PHPUnit test status: {$status}");
break;
}
return $severity;
}
/**
* Build the message string for an event
*
* @param array $event
*
* @return string
*/
protected function buildMessage($event)
{
$message = $event['test'];
if ($event['message']) {
$message .= PHP_EOL . $event ['message'];
}
return $message;
}
/**
* Build a string base trace of the failure
*
* @param array $event
*
* @return string[]
*/
protected function buildTrace($event)
{
$formattedTrace = [];
if (!empty($event['trace'])) {
foreach ($event['trace'] as $step){
$line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
$formattedTrace[] = $line;
}
}
return $formattedTrace;
}
/**
* Saves additional info for a failing test
*
* @param array $data
* @param array $event
*/
protected function getFileAndLine($event)
{
$firstTrace = end($event['trace']);
reset($event['trace']);
return [
'file' => str_replace($this->buildPath, '', $firstTrace['file']),
'line' => $firstTrace['line']
];
}
}

View file

@ -0,0 +1,130 @@
<?php
namespace PHPCensor\Plugin\Util;
/**
* Class PhpUnitResultJunit parses the results for the PhpUnitV2 plugin
*
* @author Simon Heimberg <simon.heimberg@heimberg-ea.ch>
*/
class PhpUnitResultJunit extends PhpUnitResult
{
/**
* Parse the results
*
* @return $this
* @throws \Exception If fails to parse the output
*/
public function parse()
{
$suites = simplexml_load_file($this->outputFile);
// Reset the parsing variables
$this->results = [];
$this->errors = [];
$this->failures = 0;
foreach ($suites->xpath('//testcase') as $testCase) {
$this->parseTestcase($testCase);
}
$suites['failures'];
$suites['errors'];
return $this;
}
protected function getSeverity($testCase)
{
$severity = self::SEVERITY_PASS;
foreach($testCase as $child) {
switch ($child->getName()) {
case 'failure':
$severity = self::SEVERITY_FAIL;
break 2;
case 'error':
if ('PHPUnit\Framework\RiskyTestError' == $child['type']) { // == because convertion to string is desired
$severity = self::SEVERITY_RISKY;
} else {
$severity = self::SEVERITY_ERROR;
}
break 2;
case 'skipped':
// skipped and ignored, can not distinguish
$severity = self::SEVERITY_SKIPPED;
break 2;
case 'warning':
$severity = self::SEVERITY_WARN;
break 2;
case 'system-out':
case 'system-err':
// not results
continue;
default:
$severity = 'UNKNOWN RESULT TYPE: '.$child->getName();
break 2;
}
}
return $severity;
}
protected function buildMessage($testCase)
{
$tracePos = -1;
$msg = $this->getMessageTrace($testCase);
if ('' !== $msg) {
//strip trace
$trPos = strrpos($msg, "\n\n");
if (false !== $trPos) {
$tracePos = $trPos;
$msg = substr($msg, 0, $trPos);
}
}
if ('' === $msg) {
$msg = $testCase['class'].'::'.$testCase['name'];
};
$testCase['_tracePos'] = $tracePos; // will be converted to string
return $msg;
}
protected function getOutput($testCase) {
return (string)$testCase->{'system-out'};
}
protected function buildTrace($testCase)
{
if (!is_int($testCase['_tracePos'])) {
$this->buildMessage($testCase);
}
if ($testCase['_tracePos'] >= 0) {
$stackStr = substr($this->getMessageTrace($testCase), (int)$testCase['_tracePos'] + 2, -1);
$trace = explode("\n", str_replace($this->buildPath, '.', $stackStr));
} else {
$trace = array();
}
return $trace;
}
private function getMessageTrace($testCase) {
$msg = '';
foreach($testCase as $child) {
switch ($child->getName()) {
case 'system-out':
case 'system-err':
// not results
continue;
default:
$msg = (string)$child['message']; // according to xsd
if ('' === $msg) {
$msg = (string)$child;
}
break 2;
}
}
return $msg;
}
}

View file

@ -15,8 +15,8 @@ class PhpUnitTest extends \PHPUnit_Framework_TestCase
'config' => ROOT_DIR . 'phpunit.xml'
];
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfigFile'])->getMock();
$mockPlugin->expects($this->once())->method('runConfigFile')->with(ROOT_DIR . 'phpunit.xml');
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfig'])->getMock();
$mockPlugin->expects($this->once())->method('runConfig')->with(null, ROOT_DIR . 'phpunit.xml');
$mockPlugin->execute();
}
@ -30,9 +30,10 @@ class PhpUnitTest extends \PHPUnit_Framework_TestCase
]
];
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfigFile'])->getMock();
$mockPlugin->expects($this->exactly(2))->method('runConfigFile')->withConsecutive(
[ROOT_DIR . 'phpunit1.xml'], [ROOT_DIR . 'phpunit2.xml']
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfig'])->getMock();
$mockPlugin->expects($this->exactly(2))->method('runConfig')->withConsecutive(
[null, ROOT_DIR . 'phpunit1.xml'],
[null, ROOT_DIR . 'phpunit2.xml']
);
$mockPlugin->execute();
@ -68,8 +69,8 @@ class PhpUnitTest extends \PHPUnit_Framework_TestCase
'directory' => '/test/directory/one'
];
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runDir'])->getMock();
$mockPlugin->expects($this->once())->method('runDir')->with('/test/directory/one');
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfig'])->getMock();
$mockPlugin->expects($this->once())->method('runConfig')->with('/test/directory/one', null);
$mockPlugin->execute();
}
@ -83,8 +84,8 @@ class PhpUnitTest extends \PHPUnit_Framework_TestCase
]
];
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runDir'])->getMock();
$mockPlugin->expects($this->exactly(2))->method('runDir')->withConsecutive(
$mockPlugin = $this->getPluginBuilder($options)->setMethods(['runConfig'])->getMock();
$mockPlugin->expects($this->exactly(2))->method('runConfig')->withConsecutive(
['/test/directory/one'], ['/test/directory/two']
);

View file

@ -1,11 +1,11 @@
{
"event": "suiteStart",
"suite": "Money Test Suite",
"tests": 61
"tests": 18
}{
"event": "suiteStart",
"suite": "Tests\\Money\\MoneyTest",
"tests": 15
"tests": 3
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
@ -45,24 +45,28 @@
"trace": [],
"message": "",
"output": ""
}{
"event": "suiteStart",
"suite": "ExampleResults\\ExampleFailuresTest",
"tests": 12
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure"
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure",
"status": "error",
"time": 0.0025370121002197,
"trace": [
{
"file": "\/path\/to\/build\/src\/Money.php",
"line": 335
"line": 320
},
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 43,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 15,
"function": "divide",
"class": "Money\\Money",
"type": "->"
@ -72,18 +76,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure2"
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure2"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure2",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure2",
"status": "fail",
"time": 0.008944034576416,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 61,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 20,
"function": "assertEquals",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -93,22 +97,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure3"
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testMaxInit"
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testIncomplete"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testMaxInit",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testIncomplete",
"status": "error",
"time": 0.0074319839477539,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 36,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 25,
"function": "markTestIncomplete",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -116,16 +116,20 @@
],
"message": "Incomplete Test: No yet finished...",
"output": ""
}{
"event": "testStart",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure3"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure3",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure3",
"status": "fail",
"time": 0.0014960765838623,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 66,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 30,
"function": "assertEquals",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -135,43 +139,43 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure4"
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure4"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFailure4",
"suite": "ExampleResults\\ExampleFailuresTest",
"test": "ExampleResults\\ExampleFailuresTest::testFailure4",
"status": "fail",
"time": 0.0023319721221924,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 71,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 35,
"function": "assertTrue",
"class": "PHPUnit_Framework_Assert",
"type": "::"
}
],
"message": "Really? It should have been true\nFailed asserting that false is true.",
"output": ""
"message": "Failed asserting that false is true.",
"output": "some output\nfrom f4"
}{
"event": "suiteStart",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"tests": 3
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #0 (1, 2, 3, 4, 5, 6)"
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #0 (1, 2, 3, 4, 5, 6)"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #0 (1, 2, 3, 4, 5, 6)",
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #0 (1, 2, 3, 4, 5, 6)",
"status": "fail",
"time": 0.0025498867034912,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 82,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 43,
"function": "assertSame",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -181,18 +185,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')"
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')",
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')",
"status": "fail",
"time": 0.00087904930114746,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 82,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 43,
"function": "assertSame",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -202,18 +206,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'))"
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'), array(5, 'five'), array(6, 'six'))"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testFailure5",
"test": "Tests\\Money\\MoneyTest::testFailure5 with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'))",
"suite": "ExampleResults\\ExampleFailuresTest::testFailure5",
"test": "ExampleResults\\ExampleFailuresTest::testFailure5 with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'), array(5, 'five'), array(6, 'six'))",
"status": "fail",
"time": 0.0010340213775635,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 82,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 43,
"function": "assertSame",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -223,22 +227,22 @@
"output": ""
}{
"event": "suiteStart",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"tests": 3
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #0 (1, 2, 3, 4, 5, 6)"
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #0 (1, 2, 3, 4, 5, 6)"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #0 (1, 2, 3, 4, 5, 6)",
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #0 (1, 2, 3, 4, 5, 6)",
"status": "error",
"time": 0.0041179656982422,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 99,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 51,
"function": "markTestSkipped",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -248,18 +252,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')"
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')",
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')",
"status": "error",
"time": 0.00082302093505859,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 99,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 51,
"function": "markTestSkipped",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -269,18 +273,18 @@
"output": ""
}{
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'))"
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'), array(5, 'five'), array(6, 'six'))"
}{
"event": "test",
"suite": "Tests\\Money\\MoneyTest::testSkipped",
"test": "Tests\\Money\\MoneyTest::testSkipped with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'))",
"suite": "ExampleResults\\ExampleFailuresTest::testSkipped",
"test": "ExampleResults\\ExampleFailuresTest::testSkipped with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'), array(5, 'five'), array(6, 'six'))",
"status": "error",
"time": 0.00070905685424805,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 99,
"file": "\/path\/to\/build\/tests\/ExampleFailuresTest.php",
"line": 51,
"function": "markTestSkipped",
"class": "PHPUnit_Framework_Assert",
"type": "::"
@ -288,59 +292,30 @@
],
"message": "Skipped Test: This test is currently failing",
"output": ""
}{
"event": "testStart",
"suite": "",
"test": "Tests\\Money\\MoneyTest::testDepends1"
}{
"event": "test",
"suite": "",
"test": "Tests\\Money\\MoneyTest::testDepends1",
"status": "fail",
"time": 0.00078010559082031,
"trace": [
{
"file": "\/path\/to\/build\/tests\/MoneyTest.php",
"line": 105,
"function": "assertTrue",
"class": "PHPUnit_Framework_Assert",
"type": "::"
}
],
"message": "Failed asserting that false is true.",
"output": ""
}{
"event": "test",
"suite": "",
"test": "Tests\\Money\\MoneyTest::testDepends1",
"test": "",
"status": "error",
"time": 0,
"trace": [],
"message": "Skipped Test: This test depends on \"Tests\\Money\\MoneyTest::testDepends1\" to pass.",
"message": "Skipped Test: This test depends on \"ExampleResults\\ExampleFailuresTest::testFailure\" to pass.",
"output": ""
}{
"event": "suiteStart",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest",
"tests": 23
}{
"event": "suiteStart",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser",
"tests": 18
}{
"event": "testStart",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser with data set #0 ('$1000.50', 100050)"
"suite": "",
"test": "ExampleResults\\ExampleFailuresTest::testOutput"
}{
"event": "test",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser with data set #0 ('$1000.50', 100050)",
"suite": "",
"test": "ExampleResults\\ExampleFailuresTest::testOutput",
"status": "pass",
"time": 0.0069050788879395,
"time": 0.0065488815307617,
"trace": [],
"message": "",
"output": ""
"output": "has output\non lines"
}{
"event": "testStart",
"event": "testStart",
"suite": "Tests\\Money\\MoneyTest",
"test": "Tests\\Money\\MoneyTest::testFactoryMethods"
}{
@ -352,14 +327,35 @@
"trace": [],
"message": "Trying to @cover or @use not existing method \"Monies::test\".",
"output": ""
}{
"event": "suiteStart",
"suite": "Tests\\IntlMoneyParserTest",
"tests": 2
}{
"event": "suiteStart",
"suite": "Tests\\IntlMoneyParserTest::testIntlParser",
"tests": 2
}{
"event": "testStart",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser with data set #1 ('$1000.00', 100000)"
"suite": "Tests\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\IntlMoneyParserTest::testIntlParser with data set #0 ('$1000.50', 100050)"
}{
"event": "test",
"suite": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\Money\\Parser\\IntlMoneyParserTest::testIntlParser with data set #1 ('$1000.00', 100000)",
"suite": "Tests\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\IntlMoneyParserTest::testIntlParser with data set #0 ('$1000.50', 100050)",
"status": "pass",
"time": 0.0069050788879395,
"trace": [],
"message": "",
"output": ""
}{
"event": "testStart",
"suite": "Tests\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\IntlMoneyParserTest::testIntlParser with data set #1 ('$1000.00', 100000)"
}{
"event": "test",
"suite": "Tests\\IntlMoneyParserTest::testIntlParser",
"test": "Tests\\IntlMoneyParserTest::testIntlParser with data set #1 ('$1000.00', 100000)",
"status": "pass",
"time": 0.00067996978759766,
"trace": [],

View file

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="Money Test Suite" tests="18" assertions="10" errors="3" failures="7" skipped="5" time="0.047697">
<testsuite name="Tests\Money\MoneyTest" file="/path/to/build/tests/money/tests/MoneyTest.php" tests="3" assertions="4" errors="0" failures="0" skipped="0" time="0.033813">
<testcase name="testFactoryMethods" class="Tests\Money\MoneyTest" classname="Tests.Money.MoneyTest" file="/path/to/build/tests/money/tests/MoneyTest.php" line="10" assertions="2" time="0.032037"/>
<testcase name="testJsonEncoding" class="Tests\Money\MoneyTest" classname="Tests.Money.MoneyTest" file="/path/to/build/tests/money/tests/MoneyTest.php" line="23" assertions="1" time="0.000073"/>
<testcase name="testMaxInit" class="Tests\Money\MoneyTest" classname="Tests.Money.MoneyTest" file="/path/to/build/tests/money/tests/MoneyTest.php" line="31" assertions="1" time="0.001703"/>
</testsuite>
<testsuite name="ExampleResults\ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" tests="12" assertions="6" errors="1" failures="6" skipped="5" time="0.009710">
<testcase name="testFailure" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="12" assertions="0" time="0.000107">
<error type="InvalidArgumentException">ExampleResults\ExampleFailuresTest::testFailure
InvalidArgumentException: Division by zero
/path/to/build/src/Money.php:320
/path/to/build/tests/ExampleFailuresTest.php:15
</error>
</testcase>
<testcase name="testFailure2" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="18" assertions="1" time="0.002911">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure2
Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
Money\Money Object (
- 'amount' =&gt; '2'
+ 'amount' =&gt; '3'
'currency' =&gt; Money\Currency Object (...)
)
/path/to/build/tests/ExampleFailuresTest.php:20
</failure>
</testcase>
<testcase name="testIncomplete" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="23" assertions="0" time="0.001158">
<skipped/>
</testcase>
<testcase name="testFailure3" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="28" assertions="1" time="0.000169">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure3
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
+ 0 =&gt; 3
+ 1 =&gt; 33
)
/path/to/build/tests/ExampleFailuresTest.php:30
</failure>
</testcase>
<testcase name="testFailure4" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="33" assertions="1" time="0.000648">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure4
Failed asserting that false is true.
/path/to/build/tests/ExampleFailuresTest.php:35
</failure>
<system-out>some output
from f4</system-out>
</testcase>
<testsuite name="ExampleResults\ExampleFailuresTest::testFailure5" tests="3" assertions="3" errors="0" failures="3" skipped="0" time="0.001377">
<testcase name="testFailure5 with data set #0" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="41" assertions="1" time="0.001043">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure5 with data set #0 (1, 2, 3, 4, 5, 6)
Failed asserting that 3 is identical to 1.
/path/to/build/tests/ExampleFailuresTest.php:43
</failure>
</testcase>
<testcase name="testFailure5 with data set #1" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="41" assertions="1" time="0.000188">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure5 with data set #1 ('one', 'two', 'three', 'four', 'five', 'six')
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'one'
+'three'
/path/to/build/tests/ExampleFailuresTest.php:43
</failure>
</testcase>
<testcase name="testFailure5 with data set #2" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="41" assertions="1" time="0.000146">
<failure type="PHPUnit\Framework\ExpectationFailedException">ExampleResults\ExampleFailuresTest::testFailure5 with data set #2 (array(1, 'one'), array(2, 'two'), array(3, 'three'), array(4, 'four'), array(5, 'five'), array(6, 'six'))
Failed asserting that Array &amp;0 (
0 =&gt; 3
1 =&gt; 'three'
) is identical to Array &amp;0 (
0 =&gt; 1
1 =&gt; 'one'
).
/path/to/build/tests/ExampleFailuresTest.php:43
</failure>
</testcase>
</testsuite>
<testsuite name="ExampleResults\ExampleFailuresTest::testSkipped" tests="3" assertions="0" errors="0" failures="0" skipped="3" time="0.003340">
<testcase name="testSkipped with data set #0" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="49" assertions="0" time="0.003184">
<skipped/>
</testcase>
<testcase name="testSkipped with data set #1" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="49" assertions="0" time="0.000100">
<skipped/>
</testcase>
<testcase name="testSkipped with data set #2" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="49" assertions="0" time="0.000056">
<skipped/>
</testcase>
</testsuite>
<testcase name="testDepends1" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/path/to/build/tests/ExampleFailuresTest.php" line="57" assertions="0" time="0.000000">
<skipped/>
</testcase>
<testcase name="testOutput" class="ExampleResults\ExampleFailuresTest" classname="ExampleResults.ExampleFailuresTest" file="/home/simon/var_src/php-censor.local/TMP/testResultGeneration-php-censor/ExampleResults/ExampleFailuresTest.php" line="60" assertions="1" time="0.000048">
<system-out>has output
on lines</system-out>
</testcase>
</testsuite>
<testsuite name="ExampleResults\EmptyWillWarnTest" file="/path/to/build/tests/EmptyWillWarnTest.php" tests="1" assertions="0" errors="0" failures="1" skipped="0" time="0.003860">
<testcase name="Warning" assertions="0" time="0.003860">
<warning type="PHPUnit\Framework\Warning">Warning
No tests found in class "ExampleResults\EmptyWillWarnTest".
</warning>
</testcase>
</testsuite>
<testsuite name="Tests\IntlMoneyParserTest" file="/path/to/build/tests/IntlMoneyParserTest.php" tests="2" assertions="0" errors="2" failures="0" skipped="0" time="0.000314">
<testsuite name="Tests\IntlMoneyParserTest::testIntlParser" tests="2" assertions="0" errors="2" failures="0" skipped="0" time="0.000314">
<testcase name="testIntlParser with data set #0" class="Tests\IntlMoneyParserTest" classname="Tests.IntlMoneyParserTest" file="/path/to/build/tests/IntlMoneyParserTest.php" line="14" assertions="0" time="0.000066">
<error type="PHPUnit\Framework\RiskyTestError">Risky Test
</error>
</testcase>
<testcase name="testIntlParser with data set #1" class="Tests\IntlMoneyParserTest" classname="Tests.IntlMoneyParserTest" file="/path/to/build/tests/IntlMoneyParserTest.php" line="14" assertions="0" time="0.000248">
<error type="PHPUnit\Framework\RiskyTestError">Risky Test
</error>
</testcase>
</testsuite>
</testsuite>
</testsuite>
</testsuites>

View file

@ -3,6 +3,8 @@
namespace Tests\PHPCensor\Plugin\Util;
use PHPCensor\Plugin\Util\PhpUnitResult;
use PHPCensor\Plugin\Util\PhpUnitResultJson;
use PHPCensor\Plugin\Util\PhpUnitResultJunit;
/**
* Class PhpUnitResultTest parses the results for the PhpUnitV2 plugin
@ -12,15 +14,24 @@ use PHPCensor\Plugin\Util\PhpUnitResult;
*/
class PhpUnitResultTest extends \PHPUnit_Framework_TestCase
{
/**
* Skipped test results
*
* @var array[]
*/
static $skipped = [];
public function testInitParse()
/**
* @dataProvider getTestData
*/
public function testInitParse($resultClass, $testFile)
{
$buildPath = '/path/to/build';
$parser = new PhpUnitResult(ROOT_DIR . 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt', $buildPath);
$parser = new $resultClass(ROOT_DIR . $testFile, $buildPath);
$output = $parser->parse()->getResults();
$errors = $parser->getErrors();
$this->assertEquals(8, $parser->getFailures());
$this->assertEquals(7, $parser->getFailures());
$this->assertInternalType('array', $output);
$this->assertInternalType('array', $errors);
$this->assertNotEmpty($output);
@ -30,10 +41,51 @@ class PhpUnitResultTest extends \PHPUnit_Framework_TestCase
$this->assertStringStartsNotWith($buildPath, $output[3]['trace'][0]);
$this->assertStringStartsNotWith($buildPath, $output[3]['trace'][1]);
$this->assertEquals("some output\nfrom f4", $output[7]['output']);
$this->assertEquals("has output\non lines", $output[15]['output']);
$this->assertEquals(PhpUnitResult::SEVERITY_SKIPPED, $output[5]['severity']);
$this->assertContains('Incomplete Test:', $output[5]['message']);
try {
$this->assertContains('Incomplete Test:', $output[5]['message']);
} catch (\PHPUnit_Framework_ExpectationFailedException $e) {
self::$skipped[] = ['cls' => $resultClass, 'ex' => $e];
} catch (\PHPUnit\Framework\ExpectationFailedException $e) {
self::$skipped[] = ['cls' => $resultClass, 'ex' => $e];
}
$this->assertEquals(PhpUnitResult::SEVERITY_SKIPPED, $output[11]['severity']);
$this->assertContains('Skipped Test:', $output[11]['message']);
try {
$this->assertContains('Skipped Test:', $output[11]['message']);
} catch (\PHPUnit_Framework_ExpectationFailedException $e) {
self::$skipped[] = ['cls' => $resultClass, 'ex' => $e];
} catch (\PHPUnit\Framework\ExpectationFailedException $e) {
self::$skipped[] = ['cls' => $resultClass, 'ex' => $e];
}
}
/**
* used as long as junit format does not provide message for skipped tests
*/
public function testSkippedAnything()
{
if (self::$skipped) {
$msg = "Skipped result tests:\n";
foreach (self::$skipped as $skip) {
$exMsg = strstr((string)$skip['ex'], "\n", true);
if (false === $exMsg) {
$exMsg = (string)$skip['ex'];
}
$msg .= sprintf(" * %s: %s \n", $skip['cls'], $exMsg);
}
$this->markTestSkipped($msg);
}
}
public static function getTestData()
{
return [
'json' => [PhpUnitResultJson::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt'],
'junit' => [PhpUnitResultJunit::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money_junit.xml'],
];
}
}