Unserialize error when @runInSeparateProcess
Ok, I figured out what is going on here and boy is it a doozy.
During testing the framework attempts to preserve global state. In the PHPUnit_Framework_TestCase::run()
function the current globals are converted into a string of PHP code by PHPUnit_Util_GlobalState::getGlobalsAsString()
. I am currently using an autoloading library to take care of requiring appropriate class files. This class was declared in a variable that was in the global scope, causing a serialization of that object to be put into the $GLOBALS
array created by getGlobalsAsString()
. This serialization, for whatever reason, includes the null byte character \u0000
. When you attempt to unserialize this you get an error and is ultimately causing the output to be corrupted as well.
I fixed this issue by create a function in my test bootstrap that creates the autoloading object outside of the global scope. Now that the script is no longer attempting to unserialize a null byte the script produces no errors and the test case works as expected. This is a really funky issue, not sure if its an error in my code, PHPUnit's code or an internal error with the serialize
function.
Alternatively you can override the run()
function in your test case and explicitly set the test case to not preserve global state. This is probably a cleaner solution as you could easily run into other issues with requiring all included files again as is the default behavior.
class ManagerTest extends PHPUnit_Framework_TestCase {
public function run(PHPUnit_Framework_TestResult $result = null) {
$this->setPreserveGlobalState(false);
parent::run($result);
}
}
Global state must be set before the PHPUnit_Framework_TestCase::run()
function is invoked. This is likely the only way to reliably set the global state preservation properly.
The $job argument to PHPUnit_Util_PHP::runJob()
is php code generated by PHPUnit that wraps the code of your test method in a way that it can be executed as a commandline script (clever trick!).
The isolated test will output serialized php data about test results back to phpunit.
You can investigate this code if you would add the following line on top pf PHPUnit_Util_PHP::runJob()
file_put_contents('isolated.php', $job);
After executing the failed test again the file isolated.php
should have been created in the current directory. You can have a look at code can execute it (in the current folder) by typing
php isolated.php
Do you see any output that looks messy?
Also you should debug the method PHPUnit_Util_PHP::processChildResult()
. The method is responsible for deserializing and checking test results. Place some echos or var_dumps there or use a debugger. When having a look at this method it is very likely that the problem is caused by illegal output from the test method.