Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional tests inside a standalone Symfony2's bundle

I need to make some functional tests directly in a standalone bundle. I don't want to test a controller, just some interaction between real services.

I would like to know if there is a standard/best way to do that. I did it one way but would like to know if there is a better one.

like image 855
Gnucki Avatar asked Dec 16 '14 09:12

Gnucki


1 Answers

Here is my own solution (I summarize all the process for testing in a standalone bundle):

1. First, a good bundle has its own composer.json to define its dependencies:

{
    "name": "my/own-bundle",
    "type": "symfony-bundle",
    "description": "Symfony2 bundle that provides ...",
    "keywords": ["my","own"],
    "license": "MIT",
    "authors": [
        {
            "name": "John Doe",
            "email": "[email protected]"
        }
    ],
    "require": {
        "php": ">=5.3.2",
        "symfony/framework-bundle": ">=2.3"
    },
    "require-dev": {
        "phpunit/phpunit": "3.7.*"
    },
    "autoload": {
        "psr-0": { "My\\OwnBundle": "" }
    },
    "target-dir": "My/OwnBundle",
    "minimum-stability": "dev"
}

Note the use of the dependency on symfony/framework-bundle which is needed for our tests on services. You certainly can lower the dependencies in specifying your own real dependencies on the symfony core.

With this file I can process the command (do it) to build the vendor directory of my bundle:

$ composer update

2. Then, I set my phpunit config file:

<!-- phpunit.xml.dist -->

<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
         bootstrap="Tests/bootstrap.php"
>
    <testsuites>
        <testsuite name="MyOwnBundle Test Suite">
            <directory>./Tests/</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>./</directory>
            <exclude>
                <directory>./Resources</directory>
                <directory>./Tests</directory>
                <directory>./vendor</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

3. Then, I set the php bootstrap for the autoload of the class in my test directory:

// Tests/bootstrap.php

$file = __DIR__.'/../vendor/autoload.php';
if (!file_exists($file))
{
    $file = __DIR__.'/../../../../../../vendor/autoload.php';
    if (!file_exists($file))
        throw new RuntimeException('Install dependencies to run test suite.');
}

$autoload = require_once $file;

These steps are standard for any test in a standalone bundle.

4. Now, I want to simulate an application to make some functionnal tests on my services:

I need a kernel class:

// Tests/AppKernel.php (you can define it in a subdirectory /Fixtures if you prefer)

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array();

        if (in_array($this->getEnvironment(), array('test'))) {
            $bundles[] = new Symfony\Bundle\FrameworkBundle\FrameworkBundle();
            $bundles[] = new My\OwnBundle\MyOwnBundle();
        }

        return $bundles;
    }

    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader->load(__DIR__.'/config.yml');
    }
}

And the corresponding config.yml:

# Tests/config.yml

framework:
    secret: test
    session:
        storage_id: session.storage.mock_file

my_own:
    test: 2

Here is an example with a mock for the session. Don't forget to specify the correct framework configuration nodes if you want to have access to some services (if you don't specify the node session, you have no service session for instance).

5. Finally, I can retrieve my services like the following in my test classes:

// Tests/Functional/Handling/Handler.php

namespace My\OwnBundle\Tests\Functional\Handling;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class HandlerTest extends WebTestCase
{
    private $handler;

    protected function setUp()
    {
        require_once __DIR__.'/../../AppKernel.php';

        $kernel = new \AppKernel('test', true);
        $kernel->boot();
        $container = $kernel->getContainer();
        $this->handler = $container->get('my_own.handling.handler');
    }

    public function testHandle()
    {
        $this->assert($this->handler->handle());
    }
}
like image 113
Gnucki Avatar answered Oct 19 '22 13:10

Gnucki