Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hook into PHPUnit overall test state at runtime

I have a PHPUnit bootstrap file that creates a test DB used for DB-related unit tests, and registers a shutdown function to destroy the DB once the tests complete. A fresh database for every run!

The problem: when tests fail, I want to hold onto the database for debugging purposes. At present, I have to manually disable my register_shutdown_function() call and then rerun the tests.

If I could access PHPUnit's final success/fail state for the run, I could dynamically trigger the database destruction process based on a switch within the PHPUnit bootstrap file.

PHPUnit stores this info somewhere in order to trigger the proper outcome event, i.e. the output OK vs FAILURES!. However from what I've uncovered, this information is not exposed to a user-level bootstrap file. Anyone ever done anything like this?

If you want to explore, here's a stack trace of PHPUnit that occurs when you run PHPUnit from the command line...

PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:130
PHP   4. PHPUnit_TextUI_Command->handleArguments() /usr/share/php/PHPUnit/TextUI/Command.php:139
PHP   5. PHPUnit_TextUI_Command->handleBootstrap() /usr/share/php/PHPUnit/TextUI/Command.php:620
PHP   6. PHPUnit_Util_Fileloader::checkAndLoad() /usr/share/php/PHPUnit/TextUI/Command.php:867
PHP   7. PHPUnit_Util_Fileloader::load() /usr/share/php/PHPUnit/Util/Fileloader.php:79
PHP   8. include_once() /usr/share/php/PHPUnit/Util/Fileloader.php:95
PHP   9. [YOUR PHPUNIT BOOTSTRAP RUNS HERE]
like image 356
Frank Koehl Avatar asked Sep 26 '12 14:09

Frank Koehl


1 Answers

For accessing the state of PHPUnit test cases I usually recommend using:

See the docs: PHPUnit_Framework_TestListener and how to add it to the xml config.

A small sample:

Extending the XML File with this

<listeners>
 <listener class="DbSetupListener" file="/optional/path/to/DbSetupListener.php"/>
</listeners>

Sample Listener

<?php
class DbSetupListener implements PHPUnit_Framework_TestListener {
    private $setupHappend = false;

    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {
        $this->error = true;
    }

    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {
        $this->error = true;
    }

    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) { }
    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) { }
    public function startTest(PHPUnit_Framework_Test $test) { }
    public function endTest(PHPUnit_Framework_Test $test, $time) { }

    public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
    {
        if(!$this->setupHappend) { 
            $this->setupDatabase();
            $this->setupHappend = true;
        }
    }

    public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {
        // If you have multiple test suites this is the wrong place to do anything
    }

    public function __destruct() {
        if($this->error) {
            // Something bad happend. Debug dump or whatever
        } else {
            // Teardown
        }
    }

}

This should get you going rather easy. If you need to only "listen" to specific tests or testsuites then you can use the parameters of startTest and startTestSuite.

Both objects have a getName() method that gives you the name of the test suite and test case respectively.

like image 123
edorian Avatar answered Oct 10 '22 05:10

edorian