loadOptions( $options ); } /** * An error occurred. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time */ public function addError( PHPUnit_Framework_Test $test, Exception $e, $time ) { } /** * A warning occurred. * * @param PHPUnit_Framework_Test $test * @param PHPUnit_Framework_Warning $e * @param float $time * @since Method available since Release 5.1.0 */ public function addWarning( PHPUnit_Framework_Test $test, PHPUnit_Framework_Warning $e, $time ) { } /** * A failure occurred. * * @param PHPUnit_Framework_Test $test * @param PHPUnit_Framework_AssertionFailedError $e * @param float $time */ public function addFailure( PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time ) { } /** * Incomplete test. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time */ public function addIncompleteTest( PHPUnit_Framework_Test $test, Exception $e, $time ) { } /** * Risky test. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time * @since Method available since Release 4.0.0 */ public function addRiskyTest( PHPUnit_Framework_Test $test, Exception $e, $time ) { } /** * Skipped test. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time */ public function addSkippedTest( PHPUnit_Framework_Test $test, Exception $e, $time ) { } /** * A test started. * * @param PHPUnit_Framework_Test $test */ public function startTest( PHPUnit_Framework_Test $test ) { } /** * A test ended. * * @param PHPUnit_Framework_Test $test * @param float $time */ public function endTest( PHPUnit_Framework_Test $test, $time ) { if ( ! $test instanceof PHPUnit_Framework_TestCase ) { return; } $time = $this->toMilliseconds( $time ); $threshold = $this->getSlowThreshold( $test ); if ( $this->isSlow( $time, $threshold ) ) { $this->addSlowTest( $test, $time ); } } /** * A test suite started. * * @param PHPUnit_Framework_TestSuite $suite */ public function startTestSuite( PHPUnit_Framework_TestSuite $suite ) { $this->suites++; } /** * A test suite ended. * * @param PHPUnit_Framework_TestSuite $suite */ public function endTestSuite( PHPUnit_Framework_TestSuite $suite ) { $this->suites--; if ( 0 === $this->suites && $this->hasSlowTests() ) { arsort( $this->slow ); // Sort longest running tests to the top. $this->renderHeader(); $this->renderBody(); $this->renderFooter(); } } /** * Whether the given test execution time is considered slow. * * @param int $time Test execution time in milliseconds * @param int $slow_threshold Test execution time at which a test should be considered slow (milliseconds) * @return bool */ protected function isSlow( $time, $slow_threshold ) { return $time >= $slow_threshold; } /** * Stores a test as slow. * * @param PHPUnit_Framework_TestCase $test * @param int $time Test execution time in milliseconds */ protected function addSlowTest( PHPUnit_Framework_TestCase $test, $time ) { $label = $this->makeLabel( $test ); $this->slow[ $label ] = $time; } /** * Whether at least one test has been considered slow. * * @return bool */ protected function hasSlowTests() { return ! empty( $this->slow ); } /** * Convert PHPUnit's reported test time (microseconds) to milliseconds. * * @param float $time * @return int */ protected function toMilliseconds( $time ) { return (int) round( $time * 1000 ); } /** * Label for describing a test. * * @param PHPUnit_Framework_TestCase $test * @return string */ protected function makeLabel( PHPUnit_Framework_TestCase $test ) { return sprintf( '%s:%s', get_class( $test ), $test->getName() ); } /** * Calculate number of slow tests to report about. * * @return int */ protected function getReportLength() { return min( count( $this->slow ), $this->report_length ); } /** * Find how many slow tests occurred that won't be shown due to list length. * * @return int Number of hidden slow tests */ protected function getHiddenCount() { $total = count( $this->slow ); $showing = $this->getReportLength( $this->slow ); $hidden = 0; if ( $total > $showing ) { $hidden = $total - $showing; } return $hidden; } /** * Renders slow test report header. */ protected function renderHeader() { echo sprintf( "\n\nYou should really fix these slow tests (>%sms)...\n", $this->slow_threshold ); } /** * Renders slow test report body. */ protected function renderBody() { $slow_tests = $this->slow; $length = $this->getReportLength( $slow_tests ); for ( $i = 1; $i <= $length; ++$i ) { $label = key( $slow_tests ); $time = array_shift( $slow_tests ); echo sprintf( " %s. %sms to run %s\n", $i, $time, $label ); } } /** * Renders slow test report footer. */ protected function renderFooter() { if ( $hidden = $this->getHiddenCount( $this->slow ) ) { echo sprintf( '...and there %s %s more above your threshold hidden from view', 1 === $hidden ? 'is' : 'are', $hidden ); } } /** * Populate options into class internals. * * @param array $options */ protected function loadOptions( array $options ) { $this->slow_threshold = isset( $options['slowThreshold'] ) ? $options['slowThreshold'] : 500; $this->report_length = isset( $options['reportLength'] ) ? $options['reportLength'] : 10; } /** * Get slow test threshold for given test. A TestCase can override the * suite-wide slow threshold by using the annotation @slowThreshold with * the threshold value in milliseconds. * * The following test will only be considered slow when its execution time * reaches 5000ms (5 seconds): * * * * @slowThreshold 5000 * public function testLongRunningProcess() {} * * * @param PHPUnit_Framework_TestCase $test * @return int */ protected function getSlowThreshold( PHPUnit_Framework_TestCase $test ) { $ann = $test->getAnnotations(); return isset( $ann['method']['slowThreshold'][0] ) ? $ann['method']['slowThreshold'][0] : $this->slow_threshold; } }