Timing PHPUnit Tests

Posted: 2014-12-31 11:33:58

Maybe there is a better way to do this? But using this article https://fatalfailure.wordpress.com/2011/08/22/detecting-slow-tests-with-phpunit/ I was able to find a hanging test.

Setup

I already have an xml file at the root of my project so I added to that that listener.


<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="tests/bootstrap.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="true"
         syntaxCheck="false"
>
    <listeners>
        <listener file="./app/tests/listeners/TestTimesListener.php" />
    </listeners>
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./app/tests/BehatEditor/Tests</directory>
            <directory>./app/tests/TheHub/Tests</directory>
            <exclude>./app/tests/BehatEditor/Tests/Migrations</exclude>
            <exclude>./app/tests/DMPIntegration</exclude>
        </testsuite>
    </testsuites>
</phpunit>

the lines are

    <listeners>
        <listener file="./app/tests/listeners/TestTimesListener.php" />
    </listeners>

That I added.

Then that file I ended up with this

<?php


class PHPUnitTestListener implements PHPUnit_Framework_TestListener {
    private $time;
    private $timeLimit = 0;

    public function startTest(PHPUnit_Framework_Test $test) {
        $this->time = time();
    }
    public function endTest(PHPUnit_Framework_Test $test, $time) {
        $current = time();
        $took = $current - $this->time;
        if($took > $this->timeLimit ) {
            echo "\nName: ".$test->getName()." took ".$took . " second(s) (from: $this->time, to: $current)\n";
        }
    }
    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {
    }
    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {
    }
    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time){
    }
    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {
    }
    public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {
    }
    public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {
    }

    /**
     * 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)
    {
        // TODO: Implement addRiskyTest() method.
    }
}

Right now I am only using startTest and endTest.

Finally all my tests have a TestCase class they share so in there I ended up with

<?php

use Faker\Factory as Faker;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Mockery as m;

class TestCase extends Illuminate\Foundation\Testing\TestCase {

    public function setUp()
    {
        parent::setUp();
        $this->listener = new PHPUnitTestListener();
        $this->faker = Faker::create();
        $this->prepareForTests();
        $this->listener->startTest($this);
    }

    public function tearDown()
    {
        $this->listener->endTest($this, time());
        parent::tearDown();
    }

Overall it is pretty simple once the other post pointed it out. Now to use all the other listeners.