[Symfony2] DoctrineFixturesBundleをPHPUnitと連動させる方法

2012年3月20日

symfony-logo

前回の記事で、Symfony2のblogチュートリアルにファンクショナルテストを書きました。

symfony-logo
テストコードを書きながらSymfony2のblogチュートリアルを写経した

Symfony2のblogチュートリアルにファンクショナルテストを書きながら写経してみました。 動作確認環境 Symfo ...

続きを見る

このテストにはテストメソッドの実行順序に依存関係がありました。例えば、先にデータ登録のテストを記述しないと詳細画面のテストが失敗するといった状態でした。この問題を解決するために DoctrineFixturesBundle を導入します。

動作確認環境

  • Symfony 2.0.11
  • PHP 5.3.10
  • PHPUnit 3.6.10

目次

  1. Symfony/depsファイルの編集
  2. DoctrineFixturesBundleのダウンロードとインストール
  3. Symfony/app/autoload.phpの編集
  4. Symfony/app/AppKernel.phpの編集
  5. Fixtureの作成
  6. コマンドラインからFixtureをロードする
  7. テストコードからFixtureをロードする
  8. 11章に進み、リファクタリングを行う

Symfony/depsファイルの編集

Symfony/deps ファイルに下記を追加します。私は[doctrine]ブロックの上に追加しました。

...
[doctrine-fixtures]
git=http://github.com/doctrine/data-fixtures.git
[DoctrineFixturesBundle]
git=http://github.com/doctrine/DoctrineFixturesBundle.git
target=/bundles/Symfony/Bundle/DoctrineFixturesBundle
version=origin/2.0
...

DoctrineFixturesBundleのダウンロードとインストール

DoctrineFixturesBundleをインストールするにはgitが必要です。以下の手順に進む前にgitをインストールし、githubからgit cloneできる状態にしておきます。

Symfonyのディレクトリに移動し、下記コマンドを実行します。私は念のため、apacheとmysqlを停止して実行しました。

$ php bin/vendors install --reinstall

githubよりファイルのダウンロードとインストールが行われます。

インストール完了後に Clearing the cache for the dev environment with debug true と表示されたので下記コマンドを入力してキャッシュを消しました。不要な操作かもしれませんが、念のため。

$ php app/console cache:clear --no-warmup

メモ

以前、インストールの途中で Symfony/app/cache ディレクトリに何か残っているといった内容のエラーが出たことがあります。

php app/console cache:clear --no-warmup を行なってもエラーは消えず、よく分からなかったので、sudo rm -rf Symfony/app/cache/* コマンドを実行してファイルを消し、 Symfony/app/cache ディレクトリに再度書き込み権限を与えたところうまくいきました。

キャッシュを削除したことによる影響は分かりませんが、インストール後、特に問題なく動作しているのでよしとします。

テストの実行

インストール処理でいろいろ更新されたようですので、前回の記事で作成したテストを走らせてみます。

$ phpunit -c app/

PHPUnit 3.6.10 by Sebastian Bergmann.
Configuration read from /Users/karakaram/Sites/Symfony/app/phpunit.xml.dist
........
Time: 5 seconds, Memory: 40.75Mb
OK (8 tests, 22 assertions)

大丈夫そうです。

Symfony/app/autoload.phpの編集

Symfony/app/autoload.php の $loader->registerNamespaces() メソッドの引数に下記を追加します。私は Doctrine\\Common の上に追加しました。

$loader->registerNamespaces(array(
	...
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/../vendor/doctrine-fixtures/lib',
	...
));

Symfony/app/AppKernel.phpの編集

Symfony/app/AppKernel.php の registerBundles() メソッドの $bundles 変数に下記を追加します。私は DoctrineBundle の下に追加しました。

public function registerBundles()
{
    ...
    $bundles = array(
        ...
        new Symfony\Bundle\DoctrineFixturesBundle\DoctrineFixturesBundle(),
        ...
    );
    ...
}

以上でインストールは完了です。テストを実行してアプリケーションが壊れていないことを確認してから先に進みましょう。

Fixtureの作成

DoctrineFixturesBundleでは、FixtureはPHPで記述します。csvやymlによるFixtureはサポートされていないようです。
以下、Fixtureです。ファイルの名前はマニュアルにならって、LoadPostData.php としました。

src/My/BlogBundle/DataFixtures/ORM/LoadPostData.php

namespace My\BlogBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use My\BlogBundle\Entity\Post;

/**
 * My\BlogBundle\Entity\PostエンティティのFixture
 *
 * @uses Doctrine\Common\DataFixtures\FixtureInterface
 */
class LoadPostData implements FixtureInterface
{
    /**
     * load
     *
     * @param Doctrine\Common\Persistence\ObjectManager $manager
     * @access public
     * @return void
     */
    public function load(ObjectManager $manager)
    {
        $post = new Post();
        $post->setTitle('title');
        $post->setBody('bodybodybody');
        $post->setCreatedAt(new \DateTime());
        $post->setUpdatedAt(new \DateTime());
        $manager->persist($post);
        $manager->flush();
    }
}

コマンドラインからFixtureをロードする

Fixtureができたら、コマンドラインからFixtureをロードしてみます。
下記コマンドでロードできます。--purge-with-truncate はテーブルをtruncateしてからロードするオプションです。

$ php app/console doctrine:fixtures:load --purge-with-truncate

テストコードからFixtureをロードする

前回書いたテストコードに setup() メソッドを追加し、Fixture をロードするコードを追加します。テストメソッドが実行されるごとにデータがFixtureで初期化されるようになります。

use 文がいくつか追加されていることに注意してください。

src/My/BlogBundle/Tests/Controller/DefaultControllerTest.php

namespace My\BlogBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Component\DomCrawler\Form;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use My\BlogBundle\DataFixtures\ORM\LoadPostData;

/**
 * DefaultControllerTest
 *
 * @uses Symfony\Bundle\FrameworkBundle\Test\WebTestCase
 */
class DefaultControllerTest extends WebTestCase
{
    /**
     * setUp
     *
     * @access public
     * @return void
     */
    public function setUp()
    {
        $kernel = static::createKernel();
        $kernel->boot();
        $loader = new Loader($kernel->getContainer());
        $loader->addFixture(new LoadPostData);
        $fixtures = $loader->getFixtures();
        $em = $kernel->getContainer()->get('doctrine.orm.entity_manager');
        $purger = new ORMPurger($em);
        $purger->setPurgeMode(ORMPurger::PURGE_MODE_TRUNCATE);
        $executor = new ORMExecutor($em, $purger);
        $executor->execute($fixtures);
    }
    //中略

setup() メソッドを追加したら、テストメソッドの順番を変えてテストを実行してみます。例えば、削除のテストを先頭に移動してテストを実行してみます。テストが通ればFixtureの導入は成功です。

テストコードもFixtureに合わせてリファクタリングします。

11章に進み、リファクタリングを行う

次回はblogチュートリアル(11) まとめと応用に進み、これまで書いたコードをリファクタリングしてみます。

symfony-logo
Symfony2のblogチュートリアルをリファクタリングしてみた(repositoryクラス)

前回は、blogチュートリアルを 10 章まで進め、Fixtureを導入してテストコードを書く準備を整えました。 今回は ...

続きを見る

-技術ブログ
-