Browse files

Merge pull request #62 from andho/junit

Junit
  • Loading branch information...
2 parents 54e2c1f + ac4bcb5 commit 157ec95f06d0048ce23744f809caa73f1eacccc7 @andho andho committed Sep 8, 2012
View
305 spec/Formatter/JunitSpec.php
@@ -0,0 +1,305 @@
+<?php
+
+namespace Spec\PHPSpec\Runner\Formatter;
+
+use PHPSpec\Runner\ReporterEvent;
+
+use PHPSpec\Runner\Cli\Reporter;
+
+use PHPSpec\Runner\Formatter\Junit;
+
+class DescribeJunit extends \PHPSpec\Context {
+
+ private $_reporter;
+ private $_formatter;
+ private $_doc;
+ private $_msg = 'The message. Doesn\'t matter what it is as long as it is
+ shown in the failure';
+ private $_filename = 'DummySpec.php';
+
+ public function before() {
+ $this->_reporter = $this->mock('PHPSpec\Runner\Cli\Reporter');
+
+ $formatter = new Junit($this->_reporter);
+ $formatter->update($this->_reporter, new ReporterEvent(
+ 'start',
+ '',
+ 'Dummy',
+ 0,
+ $this->_filename
+ ));
+ $this->_formatter = $formatter;
+
+ $this->_doc = new \SimpleXMLElement('<testsuites></testsuites>');
+ }
+
+ public function itFormatsPassesInJunitFormat()
+ {
+ $this->_updateFormatterWithException(
+ '.',
+ 'example1',
+ null,
+ '0.01',
+ '2',
+ 130,
+ $this->_filename
+ );
+ $this->_finishSuite();
+
+ $suite = $this->_createSuite('Dummy', 1, 0, 0, '0.01', 2,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example1', '0.01', 2, 130,
+ $this->_filename);
+
+ $this->_compare();
+ }
+
+ public function itFormatsPendingInJunitFormat()
+ {
+ $failure_e = $this->_getFailureException();
+
+ $this->_updateFormatterWithException(
+ '*',
+ 'example1',
+ $failure_e,
+ '0.01',
+ '2',
+ 50,
+ $this->_filename
+ );
+ $this->_finishSuite();
+
+ $suite = $this->_createSuite('Dummy', 1, 1, 0, '0.01', 2,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example1', '0.01', 2, 50,
+ $this->_filename);
+ // @todo try to change the type to Failure or something else
+ $fail = $this->_createFailure($case, 'example1', $failure_e, '*');
+
+ $this->_compare();
+ }
+
+ public function itFormatsFailuresInJunitFormat()
+ {
+ $failure_e = $this->_getFailureException();
+
+ $this->_updateFormatterWithException(
+ 'F',
+ 'example1',
+ $failure_e,
+ '0.01',
+ '2',
+ 250,
+ $this->_filename
+ );
+ $this->_finishSuite();
+
+ $suite = $this->_createSuite('Dummy', 1, 1, 0, '0.01', 2,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example1', '0.01', 2, 250,
+ $this->_filename);
+ // @todo try to change the type to Failure or something else
+ $fail = $this->_createFailure($case, 'example1', $failure_e, 'F');
+
+ $this->_compare();
+ }
+
+ public function itFormatsErrorsInJunitFormat()
+ {
+ $failure_e = $this->_getFailureException();
+ $this->_updateFormatterWithException(
+ 'E',
+ 'example1',
+ $failure_e,
+ '0.01',
+ '2',
+ 180,
+ $this->_filename
+ );
+ $this->_finishSuite();
+
+ $suite = $this->_createSuite('Dummy', 1, 0, 1, '0.01', 2,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example1', '0.01', 2, 180,
+ $this->_filename);
+ $fail = $this->_createFailure($case, 'example1', $failure_e, 'E');
+
+ $this->_compare();
+ }
+
+ public function itAddsUpTestsAssertionsAndTimeForSuiteFromExamples()
+ {
+ $this->_updateFormatterWithException(
+ '.',
+ 'example1',
+ null,
+ '0.01',
+ '2',
+ 130,
+ $this->_filename
+ );
+ $this->_updateFormatterWithException(
+ '.',
+ 'example2',
+ null,
+ '0.01653',
+ '5',
+ 10,
+ $this->_filename
+ );
+ $this->_finishSuite();
+
+ $suite = $this->_createSuite('Dummy', 2, 0, 0, '0.02653', 7,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example1', '0.01', 2, 130,
+ $this->_filename);
+ $case = $this->_createCase($suite, 'Dummy', 'example2', '0.01653', 5,
+ 10, $this->_filename);
+
+ $this->_compare();
+ }
+
+ private function _createFailure($case, $example, \Exception $e, $type) {
+ switch ($type) {
+ case 'E':
+ $error_type = 'ERROR';
+ $tag = 'error';
+ break;
+ case 'F':
+ $error_type = 'FAILED';
+ $tag = 'failure';
+ break;
+ case '*':
+ $error_type = 'PENDING';
+ $tag = 'failure';
+ break;
+ default:
+ throw new \Exception("Invalid type $type");
+ }
+ $failure_msg = $this->_generateFailureMessage('example1', $this->_msg, $e, $error_type);
+
+ $fail = $case->addChild($tag, $failure_msg);
+ $fail->addAttribute('type', 'Exception');
+ }
+
+ private function _getFailureException() {
+ $failure_e = new \Exception($this->_msg);
+
+ return $failure_e;
+ }
+
+ private function _generateFailureMessage($name, $msg, \Exception $exception, $type) {
+ $failure_msg = PHP_EOL . "$name ($type)" . PHP_EOL;
+ $failure_msg .= $msg . PHP_EOL;
+
+ if ($type != 'PENDING') {
+ $failure_msg .= $exception->getTraceAsString() . PHP_EOL;
+ }
+
+ return $failure_msg;
+ }
+
+ private function _updateFormatterWithException($status, $example,
+ $exception=null, $time, $assertions, $line, $file) {
+ if (is_null($exception)) {
+ $this->_formatter->update($this->_reporter, new ReporterEvent(
+ 'status',
+ $status,
+ $example,
+ $time,
+ $file,
+ $line,
+ $assertions,
+ '',
+ '',
+ null
+ ));
+ } else {
+ $this->_formatter->update($this->_reporter, new ReporterEvent(
+ 'status',
+ $status,
+ $example,
+ $time,
+ $file,
+ $line,
+ $assertions,
+ $exception->getMessage(),
+ $exception->getTraceAsString(),
+ $exception
+ ));
+ }
+ }
+
+ private function _updateFormatter($status, $example, $message,
+ $traceString, $exception, $time, $assertions, $line, $file) {
+ $this->_formatter->update($this->_reporter, new ReporterEvent(
+ 'status',
+ $status,
+ $example,
+ $time,
+ $file,
+ $line,
+ $assertions,
+ $message,
+ $traceString,
+ $exception
+ ));
+ }
+
+ private function _compare() {
+ ob_start();
+ $this->_formatter->output();
+ $output = ob_get_clean();
+
+ $dom = new \DOMDocument('1.0');
+ $dom->preserveWhitespace = false;
+ $dom->formatOutput = true;
+ $dom->loadXml($this->_doc->asXml());
+
+ $this->spec($output)
+ ->should->be($dom->saveXml());
+ }
+
+ private function _finishSuite() {
+ $this->_formatter->update($this->_reporter, new ReporterEvent('finish', '', 'Dummy'));
+ }
+
+ private function _createSuite($name, $tests, $failures, $errors,
+ $time, $assertions, $file)
+ {
+ $suite = $this->_doc->addChild('testsuite');
+ $suite->addAttribute('name', $name);
+ $suite->addAttribute('file', $file);
+
+ $suite->addAttribute('tests', $tests);
+ $suite->addAttribute('assertions', $assertions);
+ $suite->addAttribute('failures', $failures);
+ $suite->addAttribute('errors', $errors);
+ $suite->addAttribute('time', $time);
+
+ return $suite;
+ }
+
+ public function _createCase($suite, $class, $example, $time, $assertions,
+ $line, $file)
+ {
+ $case = $suite->addChild('testcase');
+ $case->addAttribute('name', $example);
+ $case->addAttribute('class', $class);
+ $case->addAttribute('file', $file);
+ $case->addAttribute('line', $line);
+ $case->addAttribute('assertions', $assertions);
+ $case->addAttribute('time', $time);
+
+ return $case;
+ }
+
+ private function _buildExpectation($expected) {
+ $output = $this->_formatStart;
+ $output .= $expected;
+ $output .= $this->_formatEnd;
+
+ return $output;
+ }
+
+}
View
151 spec/Runner/Cli/CliReporterSpec.php
@@ -0,0 +1,151 @@
+<?php
+
+use PHPSpec\Runner\Cli\Reporter;
+use PHPSpec\Runner\ReporterEvent;
+
+class DescribeCliReporter extends \PHPSpec\Context {
+
+ private $_reporter;
+ private $_formatter;
+ private $_example;
+ private $_reporterEvent;
+ private $_exception;
+
+ public function before() {
+ $this->_formatter = $this->mock('SplObserver');
+ $this->_reporter = new Reporter();
+ $this->_reporter->attach($this->_formatter);
+
+ $this->_example = $this->mock('PHPSpec\Specification\Example');
+ $this->_example->shouldReceive('getSpecificationText')
+ ->andReturn('example1');
+ $this->_example->shouldReceive('getExecutionTime')
+ ->andReturn('0.01');
+ $this->_example->shouldReceive('getNoOfAssertions')
+ ->andReturn(2);
+ $this->_example->shouldReceive('getFile')
+ ->andReturn('DummySpec.php');
+ $this->_example->shouldReceive('getLine')
+ ->andReturn(100);
+
+ $this->_reporterEvent = new ReporterEvent(
+ 'status',
+ '.',
+ 'example1',
+ '0.01',
+ null,
+ null,
+ 2
+ );
+ }
+
+ public function itNotifiesFormattersOfPassingTests() {
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent);
+
+ $this->_reporter->addPass($this->_example);
+ }
+
+ public function itNotifiesFormattersOfFailingTests() {
+ $e = new \PHPSpec\Specification\Result\Failure('Fake message');
+
+ $this->_reporterEvent->status = 'F';
+ $this->_reporterEvent->exception = $e;
+ $this->_reporterEvent->message = $e->getMessage();
+ $this->_reporterEvent->backtrace = PHPSpec\Util\Backtrace::pretty($e->getTrace());
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent);
+
+ $this->_reporter->addFailure($this->_example, $e);
+ }
+
+ public function itNotifiesFormattersOfErrorsInTests() {
+ $e = new \PHPSpec\Specification\Result\Error('Fake message');
+
+ $this->_reporterEvent->status = 'E';
+ $this->_reporterEvent->exception = $e;
+ $this->_reporterEvent->message = $e->getMessage();
+ $this->_reporterEvent->backtrace = PHPSpec\Util\Backtrace::pretty($e->getTrace());
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent);
+
+ $this->_reporter->addError($this->_example, $e);
+ }
+
+ public function itNotifiesFormattersOfExceptionsInTests() {
+ $e = new \Exception('Fake message');
+
+ $this->_reporterEvent->status = 'E';
+ $this->_reporterEvent->exception = $e;
+ $this->_reporterEvent->message = $e->getMessage();
+ $this->_reporterEvent->backtrace = PHPSpec\Util\Backtrace::pretty($e->getTrace());
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent);
+
+ $this->_reporter->addException($this->_example, $e);
+ }
+
+ public function itNotifiesFormattersOfPendingTests() {
+ $e = new \PHPSpec\Specification\Result\Pending('Fake message');
+
+ $this->_reporterEvent->status = '*';
+ $this->_reporterEvent->message = $e->getMessage();
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent);
+
+ $this->_reporter->addPending($this->_example, $e);
+ }
+
+ public function itNotifiesFormattersToExitIfFailFastIsOnAndATestFails() {
+ $e = new \Exception('Fake message');
+
+ $this->_reporterEvent->status = 'E';
+ $this->_reporterEvent->exception = $e;
+ $this->_reporterEvent->message = $e->getMessage();
+ $this->_reporterEvent->backtrace = PHPSpec\Util\Backtrace::pretty($e->getTrace());
+ $this->_reporterEvent->file = 'DummySpec.php';
+ $this->_reporterEvent->line = 100;
+
+ $reporterEvent = new Mockery\Matcher\MustBe($this->_reporterEvent);
+ $exitEvent = new Mockery\Matcher\MustBe( new ReporterEvent(
+ 'exit',
+ '',
+ ''
+ ));
+
+ $this->_reporter->setFailFast(true);
+
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $reporterEvent)->once();
+ $this->_formatter->shouldReceive('update')
+ ->with($this->_reporter, $exitEvent)->once();
+
+ $this->_reporter->addException($this->_example, $e);
+ }
+
+}
View
48 spec/Specification/InterceptorSpec.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace tests\PHPSpec\Specification\Interceptor;
+
+class DescribeInterceptor extends \PHPSpec\Context {
+
+ private $_interceptor;
+
+ public function before() {
+ $this->_interceptor = \PHPSpec\Specification\Interceptor
+ \InterceptorFactory::create(
+ new InterceptorLoop()
+ );
+ }
+
+ public function itKeepsTrackOfAssertions() {
+ $this->_interceptor->should->beAnInstanceOf(
+ 'tests\PHPSpec\Specification\Interceptor\InterceptorLoop'
+ );
+
+ $assertions = $this->_interceptor->getNumberOfAssertions();
+
+ $this->spec($assertions)->should->be(1);
+ }
+
+ public function itKeepsTrackOfAssertionsRecursively() {
+ $this->_interceptor->should->beAnInstanceOf(
+ 'tests\PHPSpec\Specification\Interceptor\InterceptorLoop'
+ );
+
+ $this->_interceptor->doSomething()->should->beAnInstanceOf(
+ 'tests\PHPSpec\Specification\Interceptor\InterceptorLoop'
+ );
+
+ $assertions = $this->_interceptor->getNumberOfAssertions();
+
+ $this->spec($assertions)->should->be(2);
+ }
+
+}
+
+class InterceptorLoop {
+
+ public function doSomething() {
+ return new InterceptorLoop();
+ }
+
+}
View
21 src/PHPSpec/Runner/Cli/Reporter.php
@@ -72,6 +72,8 @@ public function addFailure(Example $example, Failure $failure)
$this->notify(
new ReporterEvent(
'status', 'F', $example->getSpecificationText(),
+ $example->getExecutionTime(), $example->getFile(),
+ $example->getLine(), $example->getNoOfAssertions(),
$failure->getMessage(),
Backtrace::pretty($failure->getTrace()), $failure
)
@@ -90,7 +92,9 @@ public function addPass(Example $example)
$this->_passing[] = $example;
$this->notify(
new ReporterEvent(
- 'status', '.', $example->getSpecificationText()
+ 'status', '.', $example->getSpecificationText(),
+ $example->getExecutionTime(), $example->getFile(),
+ $example->getLine(), $example->getNoOfAssertions()
)
);
}
@@ -109,7 +113,8 @@ public function addDeliberateFailure(Example $example,
new ReporterEvent(
'status', 'F', $example->getSpecificationText(),
$failure->getMessage(),
- Backtrace::pretty($failure->getTrace()), $failure
+ Backtrace::pretty($failure->getTrace()), $failure,
+ $example->getExecutionTime(), $example->getNoOfAssertions()
)
);
$this->checkFailFast();
@@ -127,8 +132,10 @@ public function addError(Example $example, Error $error)
$this->notify(
new ReporterEvent(
'status', 'E', $example->getSpecificationText(),
- $error->getMessage(),
- Backtrace::pretty($error->getTrace()), $error
+ $example->getExecutionTime(), $example->getFile(),
+ $example->getLine(), $example->getNoOfAssertions(),
+ $error->getMessage(), Backtrace::pretty($error->getTrace()),
+ $error
)
);
$this->checkFailFast();
@@ -146,6 +153,8 @@ public function addException(Example $example, \Exception $e)
$this->notify(
new ReporterEvent(
'status', 'E', $example->getSpecificationText(),
+ $example->getExecutionTime(), $example->getFile(),
+ $example->getLine(), $example->getNoOfAssertions(),
$e->getMessage(), Backtrace::pretty($e->getTrace()), $e
)
);
@@ -164,7 +173,9 @@ public function addPending(Example $example, Pending $pending)
$this->notify(
new ReporterEvent(
'status', '*', $example->getSpecificationText(),
- $pending->getMessage()
+ $example->getExecutionTime(), $example->getFile(),
+ $example->getLine(), $example->getNoOfAssertions(),
+ $pending->getMessage(), null, null
)
);
}
View
164 src/PHPSpec/Runner/Formatter/Junit.php
@@ -89,9 +89,23 @@ class Junit extends Progress
/**
* Total of examples
*
- * @var string
+ * @var integer
*/
private $_total = 0;
+
+ /**
+ * Number of examples completed
+ *
+ * @var integer
+ */
+ private $_complete = 0;
+
+ /**
+ * Number of assertions made
+ *
+ * @var integer
+ */
+ private $_assertions = 0;
/**
* Tell building tool to error with status > 0
@@ -114,10 +128,11 @@ public function __construct (Reporter $reporter)
*/
public function output ()
{
- $output = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
- $output .= '<testsuites>' . PHP_EOL . $this->_result;
- $output .= '</testsuites>' . PHP_EOL;
- echo $output;
+ $dom = new \DOMDocument('1.0');
+ $dom->preserveWhitespace = false;
+ $dom->formatOutput = true;
+ $dom->loadXml($this->_xml->asXml());
+ echo $dom->saveXML();
}
/**
@@ -128,7 +143,11 @@ public function output ()
*/
protected function _startRenderingExampleGroup($reporterEvent)
{
- static $groupIndex = 1;
+ $this->_testSuite = $this->_xml->addChild('testsuite');
+ $this->_testSuite->addAttribute('name', $reporterEvent->example);
+ $this->_testSuite->addAttribute('file', $reporterEvent->file);
+
+ $this->_suiteTime = 0;
$this->_currentGroup = $reporterEvent->example;
}
@@ -138,17 +157,11 @@ protected function _startRenderingExampleGroup($reporterEvent)
*/
protected function _finishRenderingExampleGroup()
{
- $output = ' <testsuite name="'.$this->_currentGroup.'" ';
- $output .= 'tests="' . $this->_total . '" ';
- // $output .= 'assertions="' . $this->_total . '" '; not available yet
- $output .= 'failures="' . $this->_failures . '" ';
- $output .= 'errors="' . $this->_errors . '" ';
- // $output .= 'time="0.01" '; not available yet
- $output .= '>' . PHP_EOL;
- $output .= $this->_examples;
- $output .= ' </testsuite>' . PHP_EOL;
- $this->_result .= $output;
- $this->_examples = '';
+ $this->_testSuite->addAttribute('tests', $this->_total);
+ $this->_testSuite->addAttribute('assertions', $this->_assertions);
+ $this->_testSuite->addAttribute('failures', $this->_failures);
+ $this->_testSuite->addAttribute('errors', $this->_errors);
+ $this->_testSuite->addAttribute('time', $this->_suiteTime);
if ($this->_errors > 0 || $this->_failures > 0) {
$this->_errorOnExit = true;
@@ -158,6 +171,8 @@ protected function _finishRenderingExampleGroup()
$this->_failures = 0;
$this->_errors = 0;
$this->_pending = 0;
+ $this->_complete = 0;
+ $this->_assertions = 0;
}
/**
@@ -168,73 +183,64 @@ protected function _finishRenderingExampleGroup()
protected function _renderExamples($reporterEvent)
{
$this->_total++;
+ $this->_suiteTime += $reporterEvent->time;
+ $this->_assertions += $reporterEvent->assertions;
$status = $reporterEvent->status;
- $output = ' <testcase class="' . $this->_currentGroup . '"';
- $output .= ' name="' . $reporterEvent->example . '"';
- // $output .= ' file="filename.php"'; not available yet
- // $output .= ' assertions="1"'; not available yet
- // $output .= ' time="0.01"'; not available yet
- // $output .= ' line="30"'; not available yet
+ $case = $this->_testSuite->addChild('testcase');
+ $case->addAttribute('name', $reporterEvent->example);
+ $case->addAttribute('class', $this->_currentGroup);
+ $case->addAttribute('file', $reporterEvent->file);
+ $case->addAttribute('line', $reporterEvent->line);
+ $case->addAttribute('assertions', $reporterEvent->assertions);
+ $case->addAttribute('time', $reporterEvent->time);
switch ($status) {
- case '.':
- $output .= ' />' . PHP_EOL;
- $this->_examples .= $output;
- break;
- case '*':
- $error = ' <error type="';
- $error .= get_class($reporterEvent->exception) . '">';
- $error .= PHP_EOL;
- $error .= ' Skipped Test: ' . $reporterEvent->example;
- $error .= ' ' . $reporterEvent->message;
- $error .= ' </error>';
-
- $output .= '>' . PHP_EOL;
- $output .= $error . PHP_EOL;
- $output .= ' </testcase>' . PHP_EOL;
- $this->_examples .= $output;
-
- $this->_errors++;
- break;
- case 'E':
- $error = ' <error type="';
- $error .= get_class($reporterEvent->exception).'">' . PHP_EOL;
- $error .= ' ' . $reporterEvent->example . '(FAILED)';
- $error .= PHP_EOL;
- $error .= ' ' . $reporterEvent->message . PHP_EOL;
- $error .= ' ' . $reporterEvent->backtrace . PHP_EOL;
- $error .= $this->getCode($reporterEvent->exception) . PHP_EOL;
-
- $error .= ' </error>';
-
- $output .= '>' . PHP_EOL;
- $output .= $error . PHP_EOL;
- $output .= ' </testcase>' . PHP_EOL;
- $this->_examples .= $output;
-
- $this->_errors++;
- break;
- case 'F':
- $error = ' <failure type="';
- $error .= get_class($reporterEvent->exception).'">' . PHP_EOL;
-
- $error .= ' ' . $reporterEvent->example . '(FAILED)';
- $error .= PHP_EOL;
- $error .= ' ' . $reporterEvent->message . PHP_EOL;
- $error .= ' ' . $reporterEvent->backtrace . PHP_EOL;
- $error .= $this->getCode($reporterEvent->exception) . PHP_EOL;
-
- $error .= ' </failure>';
-
- $output .= '>' . PHP_EOL;
- $output .= $error . PHP_EOL;
- $output .= ' </testcase>' . PHP_EOL;
- $this->_examples .= $output;
-
- $this->_failures++;
- break;
+ case '.':
+ $this->_complete++;
+ break;
+ case '*':
+ $failureMsg = PHP_EOL . $reporterEvent->example
+ . ' (PENDING)' . PHP_EOL;
+ $failureMsg .= $reporterEvent->message . PHP_EOL;
+
+ $failure = $case->addChild('failure', $failureMsg);
+ $failure->addAttribute(
+ 'type',
+ get_class($reporterEvent->exception)
+ );
+
+ $this->_failures++;
+ break;
+ case 'E':
+ $failureMsg = PHP_EOL . $reporterEvent->example
+ . ' (ERROR)' . PHP_EOL;
+ $failureMsg .= $reporterEvent->message . PHP_EOL;
+ $failureMsg .= $reporterEvent->backtrace . PHP_EOL;
+
+ $error = $case->addChild('error', $failureMsg);
+ $error->addAttribute(
+ 'type',
+ get_class($reporterEvent->exception)
+ );
+
+ $this->_errors++;
+ break;
+ case 'F':
+ $failureMsg = PHP_EOL . $reporterEvent->example
+ . ' (FAILED)' . PHP_EOL;
+ $failureMsg .= $reporterEvent->message . PHP_EOL;
+ $failureMsg .= $reporterEvent->backtrace . PHP_EOL;
+
+ $failure = $case->addChild('failure', $failureMsg);
+ $failure->addAttribute(
+ 'type',
+ get_class($reporterEvent->exception)
+ );
+
+ $this->_failures++;
+ break;
}
}
View
6 src/PHPSpec/Runner/Reporter.php
@@ -219,8 +219,12 @@ public function exampleGroupStarted(ExampleGroup $exampleGroup)
$name = preg_replace(
'/Describe(?!.*Describe)/', '', get_class($exampleGroup)
);
+ $classRefl = new \ReflectionClass($exampleGroup);
+ $filename = $classRefl->getFileName();
$time = microtime(true);
- $this->notify(ReporterEvent::newWithTimeAndName('start', $time, $name));
+ $this->notify(
+ new ReporterEvent('start', '', $name, $time, $filename)
+ );
}
/**
View
47 src/PHPSpec/Runner/ReporterEvent.php
@@ -81,25 +81,54 @@ class ReporterEvent
public $time;
/**
+ * Number of assertions made in the example
+ *
+ * @var integer
+ */
+ public $assertions;
+
+ /**
+ * The line number that the example method starts at
+ *
+ * @var integer
+ */
+ public $line;
+
+ /**
+ * The file in which the example is in
+ *
+ * @var string
+ */
+ public $file;
+
+ /**
* Reporter event is constructed with:
*
* @param string $event
* @param string $status
* @param string $example
+ * @param float $time (OPTIONAL)
+ * @param string $file (OPTIONAL)
+ * @param integer $line (OPTIONAL)
+ * @param integer $assertions (OPTIONAL)
* @param string $message (OPTIONAL)
* @param string $trace (OPTIONAL)
* @param \Exception $exception (OPTIONAL)
*/
- public function __construct($event, $status, $example, $message = '',
- $trace = '', $e = null, $time = 0.0)
+ public function __construct($event, $status, $example, $time = null,
+ $file=null, $line=null, $assertions = null,
+ $message = null, $trace = null, $e = null)
{
- $this->status = $status;
- $this->event = $event;
- $this->example = $example;
- $this->message = $message;
- $this->backtrace = $trace;
- $this->exception = $e;
- $this->time = $time;
+ $this->status = $status;
+ $this->event = $event;
+ $this->example = $example;
+ $this->message = $message;
+ $this->backtrace = $trace;
+ $this->exception = $e;
+ $this->time = $time;
+ $this->assertions = $assertions;
+ $this->line = $line;
+ $this->file = $file;
}
/**
View
43 src/PHPSpec/Specification/BaseExample.php
@@ -65,6 +65,12 @@
* @var integer
*/
protected $_executionTime;
+ /**
+ * The number assertions made when the example is run
+ *
+ * @var integer
+ */
+ protected $_noOfAssertions;
/**
* Example keeps a reference to the example group and is created with the
@@ -109,6 +115,7 @@ public function run(Reporter $reporter)
$this->closeExample($startTime, $reporter);
return;
}
+ $this->_noOfAssertions = $this->_exampleGroup->getNumberOfAssertions();
$reporter->addPass($this);
}
@@ -173,7 +180,41 @@ public function getExecutionTime()
{
return $this->_executionTime;
}
-
+
+ /**
+ * Returns the number of assertions made in this run
+ *
+ * @return integer
+ */
+ public function getNoOfAssertions()
+ {
+ return $this->_noOfAssertions;
+ }
+
+ /**
+ * Returns the file name which contains the Spec
+ *
+ * @return string
+ */
+ public function getFile()
+ {
+ $classRefl = new \ReflectionClass($this->_exampleGroup);
+ return $classRefl->getFileName();
+ }
+
+ /**
+ * Returns the line number at which the example starts
+ *
+ * @return int
+ */
+ public function getLine()
+ {
+ $methodRefl = new \ReflectionMethod(
+ $this->_exampleGroup, $this->_methodName
+ );
+ return $methodRefl->getStartLine();
+ }
+
/**
* Closes example
*
View
28 src/PHPSpec/Specification/ExampleGroup.php
@@ -69,6 +69,13 @@ class ExampleGroup
protected $_sharedExamples = array();
/**
+ * Containes the interceptors created from this example group
+ *
+ * @var array <PHPSpec\Specification\Interceptor>
+ */
+ private $_specs = array();
+
+ /**
* Override for having it called once before all examples are ran in one
* group
*/
@@ -117,10 +124,31 @@ public function spec()
func_get_args()
);
$interceptor->setMatcherFactory($this->getMatcherFactory());
+ $this->_specs[] = $interceptor;
+
return $interceptor;
}
/**
+ * Returns the number of assertions made in the a single example
+ *
+ * @return integer
+ */
+ public function getNumberOfAssertions()
+ {
+ $assertions = 0;
+
+ foreach ($this->_specs as $spec) {
+ $assertions += $spec->getNumberOfAssertions();
+ }
+
+ // clearing the specs for the next example
+ $this->_specs = array();
+
+ return $assertions;
+ }
+
+ /**
* Marks example as pending
*
* @param string $message
View
72 src/PHPSpec/Specification/Interceptor.php
@@ -73,6 +73,20 @@
protected $_expectedValue;
/**
+ * Holds the interceptors created from within this Interceptor
+ *
+ * array <PHPSpec\Specification\Interceptor>
+ */
+ protected $_subInterceptors = array();
+
+ /**
+ * Number of assertions made
+ *
+ * @var integer
+ */
+ protected $_noOfAssertions = 0;
+
+ /**
* The matcher factory
*
* @var PHPSpec\Matcher\MatcherFactory
@@ -148,10 +162,6 @@ public function __call($method, $args)
}
- if ($this->interceptedHasAMagicCall()) {
- return $this->invokeInterceptedMagicCall($method, $args);
- }
-
if ($this->callingExpectationsAsMethods($method)) {
$this->throwErrorExpectationsAreProperties();
}
@@ -217,6 +227,32 @@ public function getExpectation()
}
/**
+ * Returns the number of assertions made in this spec
+ *
+ * @return integer
+ */
+ public function getNumberOfAssertions()
+ {
+ $assertions = $this->_noOfAssertions;
+
+ foreach ($this->_subInterceptors as $interceptors) {
+ $assertions += $interceptors->getNumberOfAssertions();
+ }
+
+ return $assertions;
+ }
+
+ /**
+ * Stores the interceptors sent from InterceptorFactory
+ *
+ * @param Interceptor $interceptor
+ */
+ public function addSubInterceptor(Interceptor $interceptor)
+ {
+ $this->_subInterceptors[] = $interceptor;
+ }
+
+ /**
* Adds a matcher
*
* @param string $matcher
@@ -288,32 +324,6 @@ protected function performMatchingWithUserDefinedMatcher($matcher,
}
/**
- * Checks if intercepted has a magic __call
- *
- * @return boolean
- */
- protected function interceptedHasAMagicCall()
- {
- return !$this->_actualValue instanceof ExampleGroup &&
- method_exists($this->_actualValue, '__call');
- }
-
- /**
- * Invokes intercepted magic call
- *
- * @param string $method
- * @param array $args
- * @return mixed
- */
- protected function invokeInterceptedMagicCall($method, $args)
- {
- $intercepted = new \ReflectionMethod($this->_actualValue, '__call');
- return InterceptorFactory::create($intercepted->invokeArgs(
- $this->_actualValue, array($method, $args)
- ));
- }
-
- /**
* Checks if intercepted is an object
*
* @return boolean
@@ -381,6 +391,8 @@ protected function throwErrorExpectationsAreProperties()
*/
protected function performMatching()
{
+ $this->_noOfAssertions++;
+
$actual = $this->getActualValue();
if (is_array($actual) && $this->_composedActual) {
View
5 src/PHPSpec/Specification/Interceptor/InterceptorFactory.php
@@ -40,6 +40,7 @@ public static function create()
{
$args = func_get_args();
$value = array_shift($args);
+ $interceptor = array_shift($args);
if (is_callable($value)) {
$spec = new Closure($value);
@@ -53,6 +54,10 @@ public static function create()
$spec = new Scalar($value);
}
+ if (!is_null($interceptor)) {
+ $interceptor->addSubInterceptor($spec);
+ }
+
return $spec;
}
}
View
57 src/PHPSpec/Specification/Interceptor/Object.php
@@ -22,6 +22,7 @@
namespace PHPSpec\Specification\Interceptor;
use PHPSpec\Specification\Interceptor;
+use PHPSpec\Specification\Interceptor\InterceptorFactory;
use PHPSpec\Matcher\InvalidMatcher;
/**
@@ -53,28 +54,33 @@ class Object extends Interceptor
*/
public function __call($method, $args)
{
+ $object = $this->getActualValue();
+ if (method_exists($object, $method)) {
+ return InterceptorFactory::create(
+ call_user_func_array(array($object, $method), $args),
+ $this
+ );
+ }
+
+ if ($method === 'property') {
+ return $this->accessProperty($args[0]);
+ }
+
$dslResult = parent::__call($method, $args);
if (!is_null($dslResult)) {
return $dslResult;
}
+ if ($this->interceptedHasAMagicCall()) {
+ return $this->invokeInterceptedMagicCall($method, $args);
+ }
+
if ($this->isPredicate('have', $method, $args) ||
$this->isPredicate('be', $method, $args)) {
$this->performPredicateMatching();
return true;
}
- $object = $this->getActualValue();
- if (method_exists($object, $method)) {
- return InterceptorFactory::create(
- call_user_func_array(array($object, $method), $args)
- );
- }
-
- if ($method === 'property') {
- return $this->accessProperty($args[0]);
- }
-
$class = get_class($object);
throw new InvalidMatcher(
"Call to undefined method {$class}::{$method}"
@@ -218,7 +224,7 @@ private function accessProperty($property)
if (array_key_exists($protected, $objectAsArray)) {
return InterceptorFactory::create($objectAsArray[$protected]);
}
-
+
foreach ($classes as $class) {
$private = sprintf("\0%s\0%s", $class, $property);
@@ -247,4 +253,31 @@ private function getClassAndParents()
}
return $classes;
}
+
+ /**
+ * Checks if intercepted has a magic __call
+ *
+ * @return boolean
+ */
+ protected function interceptedHasAMagicCall()
+ {
+ return !$this->getActualValue() instanceof ExampleGroup &&
+ method_exists($this->getActualValue(), '__call');
+ }
+
+ /**
+ * Invokes intercepted magic call
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ protected function invokeInterceptedMagicCall($method, $args)
+ {
+ $intercepted = new \ReflectionMethod($this->getActualValue(), '__call');
+ return InterceptorFactory::create($intercepted->invokeArgs(
+ $this->getActualValue(), array($method, $args)
+ ));
+ }
+
}

0 comments on commit 157ec95

Please sign in to comment.