Matthew Turland began working with PHP in 2002 and has since gone on to author php|architect's "Web Scraping with PHP," co-author SitePoint's "PHP Master: Write Cutting-Edge Code," and speak at a number of PHP conferences. In his spare time, he leads development on the Phergie project and serves as an organizer for the Acadiana Open Source Group. Matthew is a DZone MVB and is not an employee of DZone and has posted 15 posts at DZone. You can read more from them at their website. View Full User Profile

Process Isolation in PHPUnit

06.25.2011
| 5696 views |
  • submit to reddit

I was recently writing a unit test for an autoloader when I came across a somewhat unintuitive behavior in PHPUnit.

One requirement of the test suite was that some test methods had to be run in a separate process since class declarations reside in the global scope and persist until the process terminates. So, I slapped a @runInSeparateProcess annotation in the docblock of a test method with that requirement, ran the test suite… and watched that test method fail because the class was still being declared.

It took some head-scratching and tracing through the source of PHPUnit itself to figure out what was going on. When you run the phpunit executable, it’s actually instantiating PHPUnit_TextUI_TestRunner. The eventual result of this is that the run() method inherited by your subclass of PHPUnit_Framework_TestCase is called.

Depending on the value of the also-inherited $preserveGlobalState instance property, which can be set via the setPreserveGlobalState() method, multiple measures are undertaken to preserve the state of the current process. One such measure is including files for all the classes currently defined in that process, which is what was tripping me up because $preserveGlobalState has a default value of true.

$preserveGlobalState must contain its intended value before the run() method is called. The easiest way that I’ve found to facilitate this is to override the run() method in your subclass, call setPreserveGlobalState() there, then call the parent class implementation of run(). I’ve included a code sample below to illustrate this.

class MyTestCase extends PHPUnit_Framework_TestCase
{
    public function run(PHPUnit_Framework_TestResult $result = NULL)
    {
        $this->setPreserveGlobalState(false);
        return parent::run($result);
    }
}

 

So, if you try to use the @runInSeparateProcess or @runTestsInSeparateProcesses annotations that PHPUnit offers, be aware that the global state will be preserved by default. You will need to explicitly set it to not be so if running tests in separate processes is to have the effect that you are probably intending.

References
Published at DZone with permission of Matthew Turland, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: