PHPUnit: process isolation and “constant already defined”


This weekend, some WordPress core devs ported the unit tests over to a new phpunit compatible runner. I was very excited about this, particularly because the tests I maintain define a constant (DOING_AJAX) which can impact other tests.  Using process isolation should remove this impact, although at a performance cost.  I used the @runTestsInSeparateProcesses annotation, but the tests failed.  PHPUnit was restoring the global state (e.g. before the test split into a separate process) and it looked like this:

1.) Define all of the constants that were already defined
2.) Include the included files

This is the wrong process for the WordPress framework though. The included files were responsible for defining the constants. When they are included, they generate notices for defining constants that are already defined (by PHPUnit).

We all put our heads together and came up with a fix (props nacin) by hijacking PHPUnit_Framework_TestCase::prepareTemplate().

class MyTestCase extends PHPUnit_Framework_TestCase {

	/**
	 * Define constants after requires/includes
	 * @param Text_Template $template
	 * @return void
	 */
	public function prepareTemplate( Text_Template $template ) {
		$template->setVar( array(
			'constants'    => '',
			'zz_constants' => PHPUnit_Util_GlobalState::getConstantsAsString()
		));
		parent::prepareTemplate( $template );
	}
}

Yes, this is hacky, and PHPUnit warns that prepareTemplate() was deprecated in 3.4.0. But when we looked, there were no other solutions, except disabling process isolation.

4 thoughts on “PHPUnit: process isolation and “constant already defined”

  1. Another (much simpler) fix is to use the completely undocumented @preserveGlobalState disabled annotation in the test’s docblock.

Leave a comment