简体   繁体   中英

Symfony2 & PHPUnit - Access getContainer()

I have a problem with my PHPUnit test on Symfony2. To connect to my application, I use a web service, so I created a UserProvider. In my function loadUserByUsername I use Symfony2 parameters saved in app/config/parameters.yml . As I'm not in a controller I need to use the global variable $kernel and get my args like this:

global $kernel;

$url = $kernel->getContainer()-getParameter('myparam');

When I use my application, it works, but when I write my test like this:

$crawler = $client->request('GET', '/login');
$form = $crawler->selectButton('submit')->form();
$form['_username'] = $username;
$form['_password'] = $pass;

and execute PHPUnit I get this error :

Fatal error : Call to a member function getContainer()

How can I access Symfony2 parameters or use getContainer when I execute PHPUnit?

In the Symfony documentation How to Create a custom UserProvider , under 'Create a Service for the User Provider' it states:

The real implementation of the user provider will probably have some dependencies or configuration options or other services. Add these as arguments in the service definition.

So, rather than using a global $kernel variable you should be passing the relevant parameters into your user provider service by defining them as arguments in the service definition. For example:

services:
    webservice_user_provider:
        class: Acme\WebserviceUserBundle\Security\User\WebserviceUserProvider
        arguments: [%parameter_one%, %parameter_two%, ...]

As with any service, your user provider service class must then have a constructor which takes arguments corresponding to those in the service definition and stores them in private variables for use in the service's methods:

class WebserviceUserProvider implements UserProviderInterface
{
    private parameterOne;
    ...

    public function __construct($parameterOne, ...)
    {
        $this->parameterOne = $parameterOne;
        ...
    }
    ...
}

I've been writing Symfony apps for four years and I've never need to use the global $kernel variable. I daresay there may be valid circumstances but in general I'd say it's to be avoided.

First of all you should not access the kernel by using the global keyword. You can always inject it as a dependency (ie @kernel ). Still if your goal is just to access the container then you should inject just the service container which is @service_container . The right and best way is to inject just the parameters like redbirdo suggested (ie %parameter_one% , %parameter_two% ).

Regarding your test you should create and boot a propel kernel in order to be able to use it.

I suggest you create a KernelTestCase class to do that so that your test can extend it and access the container and everything like you do in your controllers.

<?php

namespace AppBundle\Tests;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase as TestCase;

/**
 * Class KernelTestCase
 * @package AppBundle\Tests
 * @author Francesco Casula <fra.casula@gmail.com>
 */
abstract class KernelTestCase extends TestCase
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

    /**
     * {@inheritdoc}
     */
    public function tearDown()
    {
        $this->container = null;
        parent::tearDown();
    }

    /**
     * @param array $options
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected function getContainer(array $options = [])
    {
        if (!$this->container) {
            static::bootKernel($options);
            $this->container = static::$kernel->getContainer();
        }

        return $this->container;
    }

    /**
     * @param string $parameter
     * @return mixed
     */
    protected function getParameter($parameter)
    {
        return $this->getContainer()->getParameter($parameter);
    }
}

And then in your test class...

<?php

namespace AppBundle\Tests\IntegrationTests;

use AppBundle\Tests\KernelTestCase as TestCase;

/**
 * Class ExampleTest
 * @package AppBundle\Tests\IntegrationTests
 * @author Francesco Casula <fra.casula@gmail.com>
 */
class ExampleTest extends TestCase
{
    public function testMyMethod()
    {
        $parameter = $this->getParameter('whatever');

        // ...

        $service = $this->getContainer()->get('service');
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM