Symfony2.6でExtensionのテストを書いてみたよってお話

Symfony2.6でExtensionのテストを書いてみたよってお話

April 9, 2015,
tags: symfony php


このエントリーをはてなブックマークに追加

今日は、初めてSymfony2のExtensionをテストコードをどのように書いたのかをブログに残しておきたいと思います。
間違っていたらぜひ指摘をしていただけると助かります…wwww

テスト対象のクラス

まずは、テスト対象のExtension, Configurationがどうなっているのか確認しましょう。
実装は以下のような形になっています。

Configuration

今回は、サーバー名、ユーザー名、パスワードが設定できるような感じだと思っていただければ大丈夫です。

// src/Polidog/SampleBundle/DependencyInjection/Configuration.php
<?php

namespace Polidog\SampleBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * This is the class that validates and merges configuration from your app/config files
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
 */
class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('polidog_sample');

        $rootNode->children()
                    ->scalarNode('server')->end()
                    ->scalarNode('username')->end()
                    ->scalarNode('password')->end()
                ->end()
            ;

        // Here you should define the parameters that are allowed to
        // configure your bundle. See the documentation linked above for
        // more information on that topic.

        return $treeBuilder;
    }
}

Extension

基本的にはBundleを生成した時と同じなのですが、サービスコンテナに値を設定しているところだけ、追記しています。

// src/Polidog/SampleBundle/DependencyInjection/PolidogSampleExtension.php
<?php

namespace Polidog\SampleBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
 * This is the class that loads and manages your bundle configuration
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
 */
class PolidogSampleExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $container->setParameter('polidog_sample.server', $config['server']);
        $container->setParameter('polidog_sample.username', $config['username']);
        $container->setParameter('polidog_sample.password', $config['password']);

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

設定ファイル

設定ファイルで以下のように、設定ができるようになっています。

# /app/config/config.yml

...

polidog_sample:
    server: "polidog.jp"
    username: "polidog"
    password: "hogehoge"

どのようなテストを書くのか考えてみる。

ここでちょっとテストの目的を考えてみましょう。

Configurationクラスでは何をテストを書くのか?

Configurationクラスはconfig.ymlでの設定をどのように書くかを定義するためのクラスです。
個人的には、モックを使った振る舞いを確認していくテストを書きたいのですが、今回の場合はgetConfigTreeBuilderメソッドの中でTreeBuilderクラスがnewされてしまっているのでモック化できません。

この場合は、仕方ないので、戻り値を元に判断をしていくのが正しいかと思います。

PolidogSampleExtensionクラスは何をテストを書くのか?

ここではサービスコンテナにパラメータをセット出来ているかということをテストすればいいのではないでしょうか?
ymlファイルのロードも行っていますが、それはYamlFileLoader側の機能なので、ここでテストするべきではないと思います。

実際テストコードをどのように書くのか?

PolidogSampleExtensionクラスに対するテストだけを書くことにしました。
Configurationクラスのロジックが複雑ではなく、PolidogSampleExtension::processConfiguration()を実行する事により、Configuration::getConfigTreeBuilder()は実行されるので、Configurationクラスに対するテストは省略します。

PolidogSampleExtensionクラスに対するテストは、パラメータがサービスコンテナにセットされているかのテストを書けばいいので、以下のようにテストを書きました。

テストコード

<?php
# src/Polidog/SampleBundle/Tests/DependencyInjection/PolidogSampleExtensionTest.php

namespace Polidog\SampleBundle\Tests\DependencyInjection;


use Symfony\Component\DependencyInjection\ContainerBuilder;
use Polidog\SampleBundle\DependencyInjection\PolidogSampleExtension;

class PolidogSampleExtensionTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @test
     */
    public function パラメータのロード処理が行える()
    {
        $configs = [
            'polidog_sample' => [
                'username' => 'username_hogehoge',
                'password' => 'password_fugafuga',
                'server' => 'polidog.jp',
            ]
        ];

        $extension = new PolidogSampleExtensionExtension();
        $container = new ContainerBuilder();
        $extension->load($configs, $container);

        $this->assertTrue($container->hasParameter('polidog_sample.username'));
        $this->assertTrue($container->hasParameter('polidog_sample.password'));
        $this->assertTrue($container->hasParameter('polidog_sample.server'));

        $this->assertEquals($configs['polidog_sample']['username'], $container->getParameter('polidog_sample.username'));
        $this->assertEquals($configs['polidog_sample']['password'], $container->getParameter('polidog_sample.password'));
        $this->assertEquals($configs['polidog_sample']['server'], $container->getParameter('polidog_sample.server'));

    }

}

Configurationクラスのロジックが複雑なら、Configurationに対してテストを行うべきですが、今回の場合は複雑ではないので、Configurationのためのテストは省略してもいいかと判断しました。

最後に

テストには様々な書き方や目的があるので、何が正解か僕にはよくわかりません。
でも、どのようなテストコードを書くのか常に考える事で、より良いコードが書けるのではないでしょうか。

comments powered by Disqus