| Q | A
| --------------------| ---------------
| PHPUnit version | 5.7.21
| PHP version | 7.0.20
| Installation Method | Composer
I discovered, that phpunit crashes with closure serialisation exception when run a test, that uses a data provider, which returns an object of Closure class, as one of elements in a dataset.
PHP Fatal error: Uncaught Exception: Serialization of 'Closure' is not allowed in /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestCase.php:814
The following test is green when running in process isolation mode turned off, but causes crash in process isolation mode turned on.
Code to reproduce error:
<?php
namespace Tests\Unit;
class FooTest extends \PHPUnit_Framework_TestCase
{
/**
* Test, that uses a data provider.
*
* @dataProvider foobarDataProvider
* @return void
*/
public function testFoobar($callback, $expected)
{
$actual = call_user_func($callback);
$this->assertEquals($expected, $actual);
}
/**
* Data provider, which returns an object of \Closure class, as one of
* elements in a dataset.
*
* @return array
*/
public function foobarDataProvider()
{
return [[
function () { return 'foo'; },
'foo',
], [
function () { return 'bar'; },
'bar',
]
];
}
}
Output:
vinter@vinter-pc /tmp/wtfunit $ ./vendor/bin/phpunit tests/Unit/FooTest.php --process-isolation
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.
PHP Fatal error: Uncaught Exception: Serialization of 'Closure' is not allowed in /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestCase.php:814
Stack trace:
#0 /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestCase.php(814): serialize(Array)
#1 /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestSuite.php(722): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#2 /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestSuite.php(722): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#3 /tmp/wtfunit/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(517): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#4 /tmp/wtfunit/vendor/phpunit/phpunit/src/TextUI/Command.php(186): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array, true)
#5 /tmp/wtfunit/vendor/phpunit/phpunit/src/TextUI/Command.php(116): PHPUnit_TextUI_Command->run(Array, true)
#6 /tmp/wtfunit/vendor/phpunit/phpunit/phpunit(52): PHPUnit_TextUI_Command::main()
#7 {main}
thrown in /tmp/wtfunit/vendor/phpunit/phpunit/src/Framework/TestCase.php on line 814
May be related to:
Is this an expected behavior?
Are objects of a Closure class allowed to be used as a dataset element in data providers? By now docs don't cover this details.
Hope this issue will help to fix it! ;)
--
Regards,
Vinter Skogen
PHP cannot serialize anonmyous functions. The process isolation feature requires serialization, for instance of the data from a data provider. So yes, this is expected behavior for now.
The implementation could be changed to only pass along the ID of the data set from the parent to the child process in which case no serialization would be required but the data provider would be executed once for each child process.
Thanks. Hop械 this will be at least documented to decrease a number of miscommunications in understanding of how the process isolation works.
If there is any way to implement support for passing anonymous functions from data provider to tests while running in process isolation mode on, that would be great. It is a really useful feature. In fact, I expect to run correctly written tests successfully (without crashes) both in default and process isolation modes. Thanks. ;)
Another way to serialize closures is to use under the hood an "uncanny" tool (yeah...) like this - https://packagist.org/packages/jeremeamia/SuperClosure. On the other hand, it is, of course, 邪 new external dependency for the phpunit.
I don't consider this a bug, just an annoyance.
Would need some convincing that phpunit should pull in a closure serialization hack out of the box, personally.
Agree, it's an annoyance. But the crash on a dummy test is caused by internal logic of framework, so, nah, it is a bug in fact, in my opinion.
Actually, I think phpunit is not a good tools.
I have got same exception in 4.6 version , also 5.* version
And the most bad thing is , It could pass test in my dev machine, and could not run when in another environment.
use bash or python to execute only one TestCase class in single process
There wont be serialization issues then.
When introducing a bug of this kind in the bootstrap file, all tests fail with the same message. It would be nice to have some kind of back trace.
I'm still figuring out why phpunit fails on perform an external library's method but my web browser doesn't show any error of any kind (even after doing error_reporting(E_ALL);ini_set('display_errors', 1);).
Having a back trace would make this easier. I don't know if this is possible or not, but if it is, then I would propose it as a feature request.
edit: Just in case it's not clear, instead of:
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
EEEEEEEEEEEEEEEEE
Time: 637 ms, Memory: 14.00MB
There were 17 errors:
1) AuditoriaTest::testSePuedeInstanciar
Exception: Serialization of 'Closure' is not allowed
2) AuditoriaTest::testSiSeAgregaUnDuplicadoSeActualiza
Exception: Serialization of 'Closure' is not allowed
...
FAILURES!
Tests: 17, Assertions: 0, Errors: 17.
Something like...
Error in the bootstrap file C:\...\bootstrap.php:
Exception: Serialization of 'Closure' is not allowed
C:\...\bootstrap.php:17
C:\...\conection.php:25
@AeonFr You said the magic word! A backtrace surely would be handy, I will do a quick investigation and report back here. I have been adding new code location hints recently, let's do some more.
Most helpful comment
Agree, it's an annoyance. But the crash on a dummy test is caused by internal logic of framework, so, nah, it is a bug in fact, in my opinion.