symfony - 在 SF3.4 及更高版本中运行 Symfony DIC 烟雾测试

标签 symfony phpunit symfony-3.4 symfony4

从 DI 容器获取服务是我的测试套件中的冒烟测试不可或缺的一部分。例如,以下测试确保容器中注册的服务的构建没有问题,并且这些服务不会花费太多时间来构建。

private const DEFAULT_TRESHOLD = 30;

public function testServicesLoadInTime()
{
    $client = static::createClient();

    /**
     * Add serviceid as key, possible values:
     * - false: Skip test for this service
     * - integer value: Custom responsetime
     */
    $customCriteria = [
        // See: https://github.com/symfony/monolog-bundle/issues/192
        'monolog.activation_strategy.not_found' => false,
        'monolog.handler.fingers_crossed.error_level_activation_strategy' => false,
        // Should not be used directly (Factories will inject other parameters)
        'liip_imagine.binary.loader.prototype.filesystem' => false,
        // Services that are allowed to load longer (Only for CLI tasks like workers)
        'assetic.asset_manager' => 1000,
    ];

    foreach ($client->getContainer()->getServiceIds() as $id) {
        if (isset($customCriteria[$id]) && $customCriteria[$id] === false) {
            continue;
        }
        try {
            $startedAt = microtime(true);
            $service = $client->getContainer()->get($id);
            $elapsed = (microtime(true) - $startedAt) * 1000;
            $this->assertNotNull($service);
            $treshold = $customCriteria[$id] ?? self::DEFAULT_TRESHOLD;
            $this->assertLessThan($treshold, $elapsed, sprintf(
                'Service %s loaded in %d ms which is more than the %d ms threshold',
                $id, $elapsed, $treshold
            ));
        } catch (InactiveScopeException $e) {
            // Noop
        } catch (\Throwable $ex) {
            $this->fail(sprintf("Fetching service %s failed: %s", $id, $ex->getMessage()));
        }
    }
}

然而。 Symfony 第 4 版将使 services private by default .即将发布的 3.4 版本在使用 get() 从服务容器获取服务时将触发弃用警告。服务未标记为公开时的方法。

这让我想知道是否有一种方法可以在不创建将所有服务作为构造函数参数的公共(public)服务的情况下保持此冒烟测试运行,而容器中有近 1000 个服务当然不是一个可行的选择。

最佳答案

这种方法with all its pros/cons is described in this post with code examples .

访问私有(private)服务的最佳解决方案是添加 一个编译器通行证,将所有服务公开以供测试 .

1.更新内核

 use Symfony\Component\HttpKernel\Kernel;
+use Symplify\PackageBuilder\DependencyInjection\CompilerPass\PublicForTestsCompilerPass;

 final class AppKernel extends Kernel
 {
     protected function build(ContainerBuilder $containerBuilder): void
     {
         $containerBuilder->addCompilerPass('...');
+        $containerBuilder->addCompilerPass(new PublicForTestsCompilerPass());
     }
 }

2. 要求或创建自己的编译器通行证

在哪里 PublicForTestsCompilerPass好像:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class PublicForTestsCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $containerBuilder): void
    {
        if (! $this->isPHPUnit()) {
            return;
        }

        foreach ($containerBuilder->getDefinitions() as $definition) {
            $definition->setPublic(true);
        }

        foreach ($containerBuilder->getAliases() as $definition) {
            $definition->setPublic(true);
        }
    }

    private function isPHPUnit(): bool
    {
        // defined by PHPUnit
        return defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__');
    }
}

要使用此类,只需通过以下方式添加包:
composer require symplify/package-builder

但当然,更好的方法是使用满足您需求的自己的类(您可以使用 Behat 进行测试等)。

然后您的所有测试将继续按预期工作!

关于symfony - 在 SF3.4 及更高版本中运行 Symfony DIC 烟雾测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46677535/

相关文章:

php - Symfony 3 设置测试数据库

mysql - 将两个 PHP 变量之间的比率显示为小数

php - Symfony 3.4 中环境特定的服务配置

mysql - SQL - 查找值相同或下一个最大的所有行

image-processing - 如何在 Symfony2 中使用 Doctrine 处理文件上传

PHPUnit Selenium 服务器 - 更好/自定义错误处理?

symfony:如何为不同环境设置配置参数文件?

symfony - 无法 Autowiring 服务 FOSUserBundle,Symfony 3.4

php - 删除方法 Symfony

php - Symfony 错误 - EntityManager#persist() 期望参数 1 是一个实体对象,数组给定