8
votes

In Symfony2, using this class setup, how can I test that each nodes is defined in the Configuration class, and that their values are correctly configured.

The class to test

# My\Bundle\DependencyInjection\Configuration.php

class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritDoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $treeBuilder->root('my_bundle')
            ->children()
                ->scalarNode("scalar")->defaultValue("defaultValue")->end()
                ->arrayNode("arrayNode")
                    ->children()
                        ->scalarNode("val1")->defaultValue("defaultValue1")->end()
                        ->scalarNode("val2")->defaultValue("defaultValue2")->end()
                    ->end()
                ->end()
            ->end()
        ;

        return $treeBuilder;
    }
}

Here are the assertions I would like to do, in my unit test:

I tried to access the nodes as an array, but it do not seems to work. Also the TreeBuilder do not seems to give us the possibility of getting the configurations as a array, unless they are loaded by the bundle extension.

Tests

# My\Bundle\Tests\DependencyInjection\ConfigurationTest.php

$configuration = $this->getConfiguration();
$treeBuilder   = $configuration->getConfigTreeBuilder();

$this->assertInstanceOf("Symfony\Component\Config\Definition\Builder\TreeBuilder", $treeBuilder);

// How to access the treebuilder's nodes ?
$rootNode   = $treeBuilder["my_bundle"];
$scalarNode = $treeBuilder["scalar"];
$arrayNode  = $treeBuilder["arrayNode"];
$val1Node   = $arrayNode["val1"];
$val2Node   = $arrayNode["val2"];

$this->assertInstanceOf("Symfony\...\ArrayNodeDefinition", $rootNode);
$this->assertEquals("defaultValue", $scalarNode, "Test the default value of the node");
$this->assertEquals("defaultValue", $val1Node, "Test the default value of the node");
$this->assertEquals("defaultValue", $val2Node, "Test the default value of the node");
2
I don't think it is actualy good idea to test configuration and also test it that way. - Ziumin
@Ziumin, What method would you suggest to ensure that a value has a default value set, or the a default service id should be confirgured... - yvoyer
I suggest preparing a test set of congigurations and checking if they are processed correctly with your Configuration class - Ziumin
@Ziumin, Would my answer be the right way too. Because, the only problem I see with it, is that The test is dedendant on another component instead of only testing the Configuration class. - yvoyer

2 Answers

11
votes

I found out a solution that could work based on JMSSecurityBundle.

Instead of testing the configuration, I test the extension which will add coverage for the configuration by the way. That way, I can assert that a default configuration was set.

For instance, this Extension.

#My\Bundle\DependencyInjection\MyBundleExtension
class MyBundleExtension extends Extension
{
    /**
     * {@inheritDoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config        = $this->processConfiguration($configuration, $configs);

        $container->setParameter("crak_landing_frontend.scalar", $config["scalar"]);
        $container->setParameter("crak_landing_frontend.array_node", $config["array_node"]);

        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.xml');
    }
}

Could be tests like:

#My\Bundle\Tests\DependencyInjection\MyBundleExtensionTest
class MyBundleExtensionTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var MyBundleExtension
     */
    private $extension;

    /**
     * Root name of the configuration
     *
     * @var string
     */
    private $root;

    public function setUp()
    {
        parent::setUp();

        $this->extension = $this->getExtension();
        $this->root      = "my_bundle";
    }

    public function testGetConfigWithDefaultValues()
    {
        $this->extension->load(array(), $container = $this->getContainer());

        $this->assertTrue($container->hasParameter($this->root . ".scalar"));
        $this->assertEquals("defaultValue", $container->getParameter($this->root . ".scalar"));

        $expected = array(
            "val1" => "defaultValue1",
            "val2" => "defaultValue2",
        );
        $this->assertTrue($container->hasParameter($this->root . ".array_node"));
        $this->assertEquals($expected, $container->getParameter($this->root . ".array_node"));
    }

    public function testGetConfigWithOverrideValues()
    {
        $configs = array(
            "scalar"     => "scalarValue",
            "array_node" => array(
                "val1" => "array_value_1",
                "val2" => "array_value_2",
            ),
        );

        $this->extension->load(array($configs), $container = $this->getContainer());

        $this->assertTrue($container->hasParameter($this->root . ".scalar"));
        $this->assertEquals("scalarValue", $container->getParameter($this->root . ".scalar"));

        $expected = array(
            "val1" => "array_value_1",
            "val2" => "array_value_2",
        );
        $this->assertTrue($container->hasParameter($this->root . ".array_node"));
        $this->assertEquals($expected, $container->getParameter($this->root . ".array_node"));
    }

    /**
     * @return MyBundleExtension
     */
    protected function getExtension()
    {
        return new MyBundleExtension();
    }

    /**
     * @return ContainerBuilder
     */
    private function getContainer()
    {
        $container = new ContainerBuilder();

        return $container;
    }
}
4
votes

To test your configuration in isolation, you can do this :

use Foo\YourBundle\DependencyInjection\Configuration;
use PHPUnit\Framework\TestCase;

class ConfigurationTest extends TestCase
{
    /**
     * @dataProvider dataTestConfiguration
     *
     * @param mixed $inputConfig
     * @param mixed $expectedConfig
     */
    public function testConfiguration($inputConfig, $expectedConfig)
    {
        $configuration = new Configuration();

        $node = $configuration->getConfigTreeBuilder()
            ->buildTree();
        $normalizedConfig = $node->normalize($inputConfig);
        $finalizedConfig = $node->finalize($normalizedConfig);

        $this->assertEquals($expectedConfig, $finalizedConfig);
    }

    public function dataTestConfiguration()
    {
        return [
            'test configuration'   => [
                ['input'],
                ['expected_config']
            ],
            // ...
        ];
    }
}