5

Symfony2、Doctrine、MongoDB を使用して安全な一連のテストを構築しようとしています。

私がする必要があるのは、テストの開始時に多くのフィクスチャをロードし、テストが終了したらアンロードすることです。transactionでやろうと思ったのですが... Doctrine と Mongo でそれを行う方法に関するドキュメントが見つかりませんでした!

ORM とのトランザクションを行う方法については Doctrine docs で良いドキュメントを見つけましたが、ODM については見つけませんでした。

そこで、Doctrine-Mongo で使用されているクラスのソース コードも調べましたが、 Connection.phpdbal バージョンbeginTransactionで使用されている,commitおよびrollbackメソッドが見つかりませんでした。

私は無知だったので、「MongoDB でロールバックすることさえ可能ですか?」と自問しました。MongoDB の FAQにある場合の答えは次のとおりです。

MongoDB は、ロールバックを伴う従来のロックや複雑なトランザクションを使用しません

beginTransaction:(だから、ODMに何もないか、まったくないのはそのためだと思います...

しかし、私の問題は残ります:テストに一種のロールバックを実装するにはどうすればよいですか?

私が今得た唯一のアイデアは、ロードしたドキュメントのすべての ID を手動で取得し、tearDown(). でも、まぁ…ちょっとヤバイですよね?

他のアイデア??

編集: この質問に対する最初のコメントの後、テストと開発で同じDBを使用したいという事実に関して、私は考えました:テストの開始時に開発データベースがコピーされる別のテストデータベースを使用しないのはなぜですか?そして、それは気楽に落とすことができますか?

それはより良いアイデアでしょうか?実際、私にはより簡単で安全に見えます。皆さんはどう思いますか?

ありがとう :)

4

2 に答える 2

4

開発用とテスト用に 2 つの別個の DB を使用していない

それが最初に対処することです-テストデータベースがないと、テストを実行すると開発データベースに影響し、その逆もまた同様であり、ひどい考えです。テストで何をしてもデプロイされたサイトに影響を与えないという絶対的な自信を持って、本番環境でテストを実行できる必要があります。

テスト接続をセットアップする

したがって、 parameters.yml を次のように変更します。

database.host: localhost
database.port: 27017
database.db:   myappname

database.test.host: localhost
database.test.port: 27017
database.test.db:   myappname-test

さらに、 app/config/config_test.yml ファイルで、デフォルトの接続をオーバーライドして、デフォルトのドキュメント マネージャーを要求するテストの一部としてトリガーするものはすべて、テスト データベースを指すマネージャーを受け取ります。

doctrine_mongodb:
    document_managers:
        default:
            database: %database.test.db%

フィクスチャを使用したテストの準備

次に、効果的にやりたいことは次のとおりです。

  • 関連するコレクションを切り捨てる
  • 負荷器具

各テストの前にテストデータベースで。

抽象テスト クラスの例を次に示します。

<?php

use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor as Executor,
    Doctrine\Common\DataFixtures\Purger\MongoDBPurger as Purger,
    Doctrine\Common\DataFixtures\Loader,
    Doctrine\Common\DataFixtures\ReferenceRepository,
    Symfony\Bundle\FrameworkBundle\Test\WebTestCase,
    Symfony\Bundle\FrameworkBundle\Console\Application;

abstract class AbstractTest extends WebTestCase
{
    /**
     * Array of fixtures to load.
     */
    protected $fixtures = array();

    /**
     * Setup test environment
     */
    public function setUp()
    {
        $kernel = static::createKernel(array('environment' => 'test', 'debug' => false));
        $kernel->boot();
        $this->container = $kernel->getContainer();
        $this->dm = $this->container->get('doctrine.odm.mongodb.document_manager');

        if ($this->fixtures) {
            $this->loadFixtures($this->fixtures, false);
        }
    }

    /**
     * Load fixtures
     *
     * @param array   $fixtures names of _fixtures to load
     * @param boolean $append   append data, or replace?
     */
    protected function loadFixtures($fixtures = array(), $append = true)
    {
        $defaultFixtures = false;

        $loader = new Loader();
        $refRepo = new ReferenceRepository($this->dm);

        foreach ((array) $fixtures as $name) {
            $fixture = new $name();
            $fixture->setReferenceRepository($refRepo);
            $loader->addFixture($fixture);
        }

        $purger = new Purger();
        $executor = new Executor($this->dm, $purger);
        $executor->execute($loader->getFixtures(), $append);
    }
}

テストでフィクスチャを使用する

前の抽象テスト クラスを使用すると、必要に応じて、フィクスチャ データを使用するかどうかにかかわらず、テストを作成できます。以下は簡単な例です。

<?php

use Your\AbstractTest,
    Your\Document\Foo;

class RandomTest extends AbstractTest
{
    /**
     * fixtures to load before each test
     */
    protected $fixtures = array(
        'APP\FooBundle\DataFixtures\MongoDB\TestFoos',
        'APP\FooBundle\DataFixtures\MongoDB\TestBars'
    );

    ...

    /**
     * Check it gets an ID (insert succeeded)
     * 
     */
    public function testCreateDefaults()
    {
        $foo = new Foo();
        $this->dm->persist($foo);
        $this->dm->flush();

        $this->assertNotNull($foo->getId());
        $this->assertSame('default value', $foo->getSomeProperty());
        // etc.
    }

    /**
     * Check result of something with a given input
     * 
     */
    public function testSomething()
    {
        $foo = $this->dm->getRepository(APPFooBundle:Foo)->findByName('Some fixture object');

        $foo->doSomething();
        $this->assertSame('modified value', $foo->getSomeProperty());
        // etc.
    }

各テストの前に、定義したフィクスチャがロードされ (それらが影響するコレクションを切り捨て)、テストのベースとなる一貫したデータベース状態を提供します。

于 2012-04-04T14:30:46.237 に答える
2

各テストの前にMongoDBデータベースを削除してから、必要なフィクスチャをロードするだけです。このようにして、各テストは完全に分離されます。

于 2012-04-04T14:15:29.870 に答える