123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- <?php
- /**
- * A PHPUnit TestListener that exposes your slowest running tests by outputting
- * results directly to the console.
- */
- class SpeedTrapListener implements PHPUnit_Framework_TestListener {
- /**
- * Internal tracking for test suites.
- *
- * Increments as more suites are run, then decremented as they finish. All
- * suites have been run when returns to 0.
- *
- * @var integer
- */
- protected $suites = 0;
- /**
- * Time in milliseconds at which a test will be considered "slow" and be
- * reported by this listener.
- *
- * @var int
- */
- protected $slow_threshold;
- /**
- * Number of tests to report on for slowness.
- *
- * @var int
- */
- protected $report_length;
- /**
- * Collection of slow tests.
- *
- * @var array
- */
- protected $slow = array();
- /**
- * Construct a new instance.
- *
- * @param array $options
- */
- public function __construct( array $options = array() ) {
- $this->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):
- *
- * <code>
- *
- * @slowThreshold 5000
- * public function testLongRunningProcess() {}
- * </code>
- *
- * @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;
- }
- }
|