Phpunit: Serialization of 'Closure' is not allowed exception when run tests in process isolation mode

Created on 15 Jul 2017  路  10Comments  路  Source: sebastianbergmann/phpunit

| 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

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.

All 10 comments

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.

Do you think it would be a good idea to do that:

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.

Was this page helpful?
0 / 5 - 0 ratings