3 * This file is part of PHPUnit.
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
12 * A TestListener that generates a logfile of the test execution in XML markup.
14 * The XML markup used is the same as the one that is used by the JUnit Ant task.
16 * @since Class available since Release 2.1.0
18 class PHPUnit_Util_Log_JUnit extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
33 protected $logIncompleteSkipped = false;
38 protected $writeDocument = true;
43 protected $testSuites = array();
48 protected $testSuiteTests = array(0);
53 protected $testSuiteAssertions = array(0);
58 protected $testSuiteErrors = array(0);
63 protected $testSuiteFailures = array(0);
68 protected $testSuiteTimes = array(0);
73 protected $testSuiteLevel = 0;
78 protected $currentTestCase = null;
83 protected $attachCurrentTestCase = true;
89 * @param bool $logIncompleteSkipped
91 public function __construct($out = null, $logIncompleteSkipped = false)
93 $this->document = new DOMDocument('1.0', 'UTF-8');
94 $this->document->formatOutput = true;
96 $this->root = $this->document->createElement('testsuites');
97 $this->document->appendChild($this->root);
99 parent::__construct($out);
101 $this->logIncompleteSkipped = $logIncompleteSkipped;
105 * Flush buffer and close output.
107 public function flush()
109 if ($this->writeDocument === true) {
110 $this->write($this->getXML());
119 * @param PHPUnit_Framework_Test $test
120 * @param Exception $e
123 public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
125 if ($this->currentTestCase === null) {
129 if ($test instanceof PHPUnit_Framework_SelfDescribing) {
130 $buffer = $test->toString() . PHP_EOL;
135 if ($e instanceof PHPUnit_Framework_ExceptionWrapper) {
136 $type = $e->getClassname();
137 $buffer .= (string) $e;
139 $type = get_class($e);
140 $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) . PHP_EOL .
141 PHPUnit_Util_Filter::getFilteredStacktrace($e);
144 $error = $this->document->createElement(
146 PHPUnit_Util_XML::prepareString($buffer)
149 $error->setAttribute('type', $type);
151 $this->currentTestCase->appendChild($error);
153 $this->testSuiteErrors[$this->testSuiteLevel]++;
157 * A failure occurred.
159 * @param PHPUnit_Framework_Test $test
160 * @param PHPUnit_Framework_AssertionFailedError $e
163 public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
165 if ($this->currentTestCase === null) {
169 if ($test instanceof PHPUnit_Framework_SelfDescribing) {
170 $buffer = $test->toString() . "\n";
175 $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) .
177 PHPUnit_Util_Filter::getFilteredStacktrace($e);
179 $failure = $this->document->createElement(
181 PHPUnit_Util_XML::prepareString($buffer)
184 $failure->setAttribute('type', get_class($e));
186 $this->currentTestCase->appendChild($failure);
188 $this->testSuiteFailures[$this->testSuiteLevel]++;
194 * @param PHPUnit_Framework_Test $test
195 * @param Exception $e
198 public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
200 if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
201 $error = $this->document->createElement(
203 PHPUnit_Util_XML::prepareString(
204 "Incomplete Test\n" .
205 PHPUnit_Util_Filter::getFilteredStacktrace($e)
209 $error->setAttribute('type', get_class($e));
211 $this->currentTestCase->appendChild($error);
213 $this->testSuiteErrors[$this->testSuiteLevel]++;
215 $this->attachCurrentTestCase = false;
222 * @param PHPUnit_Framework_Test $test
223 * @param Exception $e
226 * @since Method available since Release 4.0.0
228 public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
230 if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
231 $error = $this->document->createElement(
233 PHPUnit_Util_XML::prepareString(
235 PHPUnit_Util_Filter::getFilteredStacktrace($e)
239 $error->setAttribute('type', get_class($e));
241 $this->currentTestCase->appendChild($error);
243 $this->testSuiteErrors[$this->testSuiteLevel]++;
245 $this->attachCurrentTestCase = false;
252 * @param PHPUnit_Framework_Test $test
253 * @param Exception $e
256 * @since Method available since Release 3.0.0
258 public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
260 if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
261 $error = $this->document->createElement(
263 PHPUnit_Util_XML::prepareString(
265 PHPUnit_Util_Filter::getFilteredStacktrace($e)
269 $error->setAttribute('type', get_class($e));
271 $this->currentTestCase->appendChild($error);
273 $this->testSuiteErrors[$this->testSuiteLevel]++;
275 $this->attachCurrentTestCase = false;
280 * A testsuite started.
282 * @param PHPUnit_Framework_TestSuite $suite
284 * @since Method available since Release 2.2.0
286 public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
288 $testSuite = $this->document->createElement('testsuite');
289 $testSuite->setAttribute('name', $suite->getName());
291 if (class_exists($suite->getName(), false)) {
293 $class = new ReflectionClass($suite->getName());
295 $testSuite->setAttribute('file', $class->getFileName());
296 } catch (ReflectionException $e) {
300 if ($this->testSuiteLevel > 0) {
301 $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite);
303 $this->root->appendChild($testSuite);
306 $this->testSuiteLevel++;
307 $this->testSuites[$this->testSuiteLevel] = $testSuite;
308 $this->testSuiteTests[$this->testSuiteLevel] = 0;
309 $this->testSuiteAssertions[$this->testSuiteLevel] = 0;
310 $this->testSuiteErrors[$this->testSuiteLevel] = 0;
311 $this->testSuiteFailures[$this->testSuiteLevel] = 0;
312 $this->testSuiteTimes[$this->testSuiteLevel] = 0;
318 * @param PHPUnit_Framework_TestSuite $suite
320 * @since Method available since Release 2.2.0
322 public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
324 $this->testSuites[$this->testSuiteLevel]->setAttribute(
326 $this->testSuiteTests[$this->testSuiteLevel]
329 $this->testSuites[$this->testSuiteLevel]->setAttribute(
331 $this->testSuiteAssertions[$this->testSuiteLevel]
334 $this->testSuites[$this->testSuiteLevel]->setAttribute(
336 $this->testSuiteFailures[$this->testSuiteLevel]
339 $this->testSuites[$this->testSuiteLevel]->setAttribute(
341 $this->testSuiteErrors[$this->testSuiteLevel]
344 $this->testSuites[$this->testSuiteLevel]->setAttribute(
346 sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])
349 if ($this->testSuiteLevel > 1) {
350 $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel];
351 $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel];
352 $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel];
353 $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel];
354 $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel];
357 $this->testSuiteLevel--;
363 * @param PHPUnit_Framework_Test $test
365 public function startTest(PHPUnit_Framework_Test $test)
367 $testCase = $this->document->createElement('testcase');
368 $testCase->setAttribute('name', $test->getName());
370 if ($test instanceof PHPUnit_Framework_TestCase) {
371 $class = new ReflectionClass($test);
372 $methodName = $test->getName();
374 if ($class->hasMethod($methodName)) {
375 $method = $class->getMethod($test->getName());
377 $testCase->setAttribute('class', $class->getName());
378 $testCase->setAttribute('file', $class->getFileName());
379 $testCase->setAttribute('line', $method->getStartLine());
383 $this->currentTestCase = $testCase;
389 * @param PHPUnit_Framework_Test $test
392 public function endTest(PHPUnit_Framework_Test $test, $time)
394 if ($this->attachCurrentTestCase) {
395 if ($test instanceof PHPUnit_Framework_TestCase) {
396 $numAssertions = $test->getNumAssertions();
397 $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
399 $this->currentTestCase->setAttribute(
405 $this->currentTestCase->setAttribute(
410 $this->testSuites[$this->testSuiteLevel]->appendChild(
411 $this->currentTestCase
414 $this->testSuiteTests[$this->testSuiteLevel]++;
415 $this->testSuiteTimes[$this->testSuiteLevel] += $time;
417 if (method_exists($test, 'hasOutput') && $test->hasOutput()) {
418 $systemOut = $this->document->createElement('system-out');
419 $systemOut->appendChild(
420 $this->document->createTextNode($test->getActualOutput())
422 $this->currentTestCase->appendChild($systemOut);
426 $this->attachCurrentTestCase = true;
427 $this->currentTestCase = null;
431 * Returns the XML as a string.
435 * @since Method available since Release 2.2.0
437 public function getXML()
439 return $this->document->saveXML();
443 * Enables or disables the writing of the document
446 * This is a "hack" needed for the integration of
447 * PHPUnit with Phing.
451 * @since Method available since Release 2.2.0
453 public function setWriteDocument($flag)
455 if (is_bool($flag)) {
456 $this->writeDocument = $flag;