Symfony FormType testing deal with EntityType Symfony FormType testing deal with EntityType symfony symfony

Symfony FormType testing deal with EntityType


I struggled with unit testing something that relies on a service container a great deal. At first I tried mocking everything, like you did. This can make a unit test pass with great effort (services have a tendency to rely on still other services in Symfony, which will also have to be mocked), but it takes even more effort to make sure that passing the test means that it would work with the data you want it to work with.

Additionally, unit testing a database is notoriously difficult and rarely discussed. I am not sure if what I'm sharing is the "best" answer, but it is an answer which worked for me and it helps to unit test the real services. As such I have found it to be a more effective method to testing than mocking the services.

This is based on a great article, which, of course, I can't locate now (I will update this if I find it to credit them).

Basically, you can set up your bundles to have containers in testing.

composer.json:

"require-dev": {    "sensio/framework-extra-bundle": ">=3.0",    "symfony/asset": ">=3.2"}

Then create a config.yml with any services you might need and the bare minimum for Symfony forms:

framework:    secret: 'shh'    form: ~    validation: { enable_annotations: true }    session:        storage_id: session.storage.mock_filedoctrine:    # your doctrine settings if you want to test against the DB

Create an AppKernel class.

class AppKernel extends Kernel{    public function registerBundles()    {        return array(            new FrameworkBundle(),            new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),            // any other bundles you need        );    }    public function registerContainerConfiguration(LoaderInterface $loader)    {        $loader->load(__DIR__.'/config.yml');    }    public function getLogDir()    {        return '/tmp/log/' . $this->environment;    }}

Finally, I create a helper class in my base TestCase:

protected function getContainer(){    if (!isset($this->kernel)) {        $this->kernel = new AppKernel('test', true);        $this->kernel->boot();    }    if (!isset($this->container)) {        $this->container = $this->kernel->getContainer();    }    return $this->container;}

Now you can access any services that you have registered like this:

public function testContainerAccess(){    $this->assertTrue(is_object($this->getContainer());    $this->assertTrue($this->getContainer()->get('doctrine.orm.entity_manager') instanceof \Doctrine\ORM\EntityManagerInterface);}

Testing against a database is always tricky and is a separate can of worms. In this case the easiest thing to do would probably be to create a separate testing schema and run your queries against that.

Hope this helps.