How to access a private service in Symfony 3.4 phpunit tests?

删除回忆录丶 提交于 2019-12-20 03:04:42

问题


I want to test a service who send mail. I have create a unit test but i have some deprecation warning and i want to know the good use. In my setUp() function i get the service like this

    $this->container = self::$kernel->getContainer();
    $this->swiftMailer = $this->container->get('swiftmailer.mailer');

But i have this message

The "swiftmailer.mailer" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.

What is the best pratice to do ? I have the same message for security.authentication.manager


回答1:


Services were made private by default in Symfony 3.4.

Symfony 4.1

Starting with Symfony 4.1 all private services are made available in test environment via a special test container:

class FooTest extends KernelTestCase
{
    static::bootKernel();
    $this->swiftmailer = static::$container->get('swiftmailer.mailer');
}

Symfony 3.4 and 4.0

One way you could solve it in Symfony 3.4 and 4.0 is to register a service locator in test environment, that would expose private services you need access to in tests.

Another way would be to simply create a public alias for each private service you need access to in tests.

For example:

# app/config/config_test.yml
services:
    test_alias.swiftmailer.mailer:
        alias: '@swiftmailer.mailer'
        public: true

In your test you'll be now able to access your private service via the public alias test_alias.swiftmailer.mailer:

$this->container = self::$kernel->getContainer();
$this->swiftMailer = $this->container->get('test_alias.swiftmailer.mailer');



回答2:


This approach with all its pros/cons is described in this post with code examples.


There is no need to extend and maintain extra configs lines for tests. There should be no public: true in them:

The best solution to access private services is to add a Compiler Pass that makes all services public for tests.

1. Update Kernel

 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. Require or create own Compiler Pass

Where PublicForTestsCompilerPass looks like:

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__');
    }
}

To use this class, just add the package by:

composer require symplify/package-builder

But of course, the better way is to use own class, that meets your needs (you might Behat for tests etc.).

Then all your tests will keep working as expected!

Let me know, how that works for you.



来源:https://stackoverflow.com/questions/49938021/how-to-access-a-private-service-in-symfony-3-4-phpunit-tests

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!