【问题标题】:How to avoid Serialization of Closure with process isolation on PHPUnit?如何通过 PHPUnit 上的进程隔离来避免闭包的序列化?
【发布时间】:2021-09-23 10:46:38
【问题描述】:

我正在尝试为 nextcloud 的扩展(应用程序)编写集成测试。 Nextcloud 本身是基于 Symfony 的。长话短说,到目前为止,我以一个测试类结束,它抛出了以下错误消息:

PHPUnit 8.5.15 by Sebastian Bergmann and contributors.

IE                                                                  2 / 2 (100%)

Time: 642 ms, Memory: 24.00 MB

There was 1 error:

1) tests\Integration\Setup\Migrations\Version000000Date20210701093123Test::testRedundantEntriesInDB with data set "caseC" (array(), array('bob'))
PHPUnit\Framework\Exception: PHP Fatal error:  Uncaught Exception: Serialization of 'Closure' is not allowed in Standard input code:340
Stack trace:
#0 Standard input code(340): serialize(Array)
#1 Standard input code(1237): __phpunit_run_isolated_test()
#2 {main}
  thrown in Standard input code on line 340

ERRORS!
Tests: 2, Assertions: 1, Errors: 1, Incomplete: 1.

我试图找到这个错误的罪魁祸首,据我所知,这是因为我使用 @runInSeparateProcess 作为命名测试的注释,并且 PHPUnit 尝试的一些全局状态似乎存在为子 PHP 进程保存/序列化。

简化的 MWE 代码可在in a branch on github 或以下获取,以供以后参考。 在阅读Symfony 2 + Doctrine 2 + PHPUnit 3.5: Serialization of closure exception 和此处的类似问题后,我试图缩小问题范围。 created container 是某种全局存储,它将保存依赖注入方法的各种实例。

如何避免 PHPUnit 试图保持这种状态?事实上,我使用进程分离来为测试提供一个干净的启动环境。

让我有点吃惊的是,只有当数据提供者的第二个函数参数是非空数组时才会出现错误。

如果需要,可以克隆 repo 并构建一些 docker 容器(在 Linux 下,IDK 关于 Windows)来手动运行测试。只需转到.github/actions/run-tests 并致电./run-locally.sh --prepare stable21 来构建环境(喝一大杯咖啡)。然后可以用./run-locally.sh --run-integration-tests --filter 'tests\\Integration\\Setup\\Migrations\\Version000000Date20210701093123Test'开始测试。


这里是基本的 MWE 代码:

<?php

namespace tests\Integration\Setup\Migrations;

use OCP\AppFramework\App;
use OCP\AppFramework\IAppContainer;
use PHPUnit\Framework\TestCase;

class Version000000Date20210701093123Test extends TestCase {
    
    /**
     * @var IAppContainer
     */
    private $container;
    
    public function setUp(): void {
        parent::setUp();
        
        $app = new App('cookbook');
        $this->container = $app->getContainer();
    }
    
    /**
     * @dataProvider dataProvider
     * @runInSeparateProcess
     */
    public function testRedundantEntriesInDB($data, $updatedUsers) {
//         print_r($updatedUsers);
        sort($updatedUsers);
//         print_r($updatedUsers);
        
        $this->assertEquals($updatedUsers, []);
        
        $this->markTestIncomplete('Not yet implemented');
    }
    
    public function dataProvider() {
        return [
            'caseB' => [
                [
                ],
                [],
            ],
            'caseC' => [
                [
                ],
                ['bob']
            ],
        ];
    }
}

【问题讨论】:

标签: php phpunit integration-testing nextcloud


【解决方案1】:

当测试运行程序创建运行测试的计划时,它会收集需要执行哪些数据集的测试方法。

为此,获取数据集。

现在对于测试方法,需要进程隔离 (@runInSeparateProcess)。因此,test-method 在它自己的 PHP 进程中被调用,数据集中用来调用它的记录被传递给它。

由于这是一个单独的过程,因此数据集被序列化(编组),以便可以在运行测试的单独测试过程中进行反序列化(解组)。

如果数据集中包含拒绝序列化的数据,则无法执行测试。

类似地,如果测试执行但结果包含无法序列化的数据(以便可以将其传递回主运行程序进程),则测试也会失败。

后者可能是你的情况。

无法序列化数据是 PHP 中的一个致命错误,这意味着单独的 php 进程在错误hard中退出。由于它是一个单独的进程,它可以被 phpunit runner 捕获,但测试被标记为错误。


  • tearDown 方法添加到测试用例。
  • 在拆卸时取消设置$this-&gt;container
  • 再试一次。
  • 可能不适用:众所周知,Symfony 可以在各种缓存上运行,检查 $GLOBALS 可能会揭示一些关于如何正确杀死 应用程序的见解> 如果它拒绝离开)

【讨论】:

  • 来自单独进程的参数和来自单独进程的参数都应该只是字符串数组。我通过注释掉断言(允许测试顺利运行)并打印返回的变量的gettype() 来检查。此外,如果您仔细观察,在我的 MWE 中,我只是对输入变量进行断言。测试中不产生任何输出。 -> 从数据提供者到单独进程的传输会导致问题。
  • 我能理解这种感觉,但请记住,致命错误通常不会骗你;)我的猜测是它在传回。这包括很大一部分测试运行器,它可能连接到一些不直接可见的部分。也许借助 xdebug 3,由于环境配置,您可以进行单步调试,包括。错误断点,以便更好地了解那个孤立的 PHP 进程。
  • 但是对于分步调试,我还需要一个源代码(除了在 docker 容器进程的子进程中调试......你明白了)。因为执行的 PHP 代码通过管道作为标准输入/标准输出对从 PHPUnit 主进程传输到 PHP 子进程,所以很难在那里挖掘。还是我被误导了?
  • 这是一个很好的观点。您的 IDE 不会找到源代码,但会找到包含堆栈在内的堆栈。变量应该是可用的。无论如何,这将是您真正想要挖掘它的方向。 --- 这听起来像是一个巨大的装置。你能关闭被测系统,以便在测试完成后尽可能清理干净吗?您也可以尝试隔离,例如单一测试方法,一个数据集,然后正常运行,进行检查等。---杀死::tearDown中的容器,它被分配给测试用例实例(例如unset())。
  • @ChristianWolf:是的,对于 _G 来说是真的...,已修复。 - 还有a command line debug client 可能会产生更快的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-25
  • 1970-01-01
相关资源
最近更新 更多