Reputation: 525
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?
Upvotes: 2
Views: 4272
Reputation: 27130
First of all you should not access the kernel by using the global
keyword. You can always inject it as a dependency (i.e. @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 (i.e. %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 <[email protected]>
*/
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 <[email protected]>
*/
class ExampleTest extends TestCase
{
public function testMyMethod()
{
$parameter = $this->getParameter('whatever');
// ...
$service = $this->getContainer()->get('service');
}
}
Upvotes: 2
Reputation: 4957
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.
Upvotes: 2