Symfony2 Doctrine MongoDB回滚

时间:2012-04-04 14:06:14

标签: php mongodb symfony tdd doctrine-orm

我正在尝试使用Symfony2,Doctrine和MongoDB构建一组安全的测试。

我需要做的是在测试开始时加载很多灯具,并在它结束时卸载它们。我想过用交易来做这件事,但是......我找不到有关如何用Doctrine和Mongo做的文档!

我在Doctrine文档中找到了关于如何与ORM进行交易的good documentation,但没有关于ODM。

所以我看了一下Doctrine-Mongo使用的source code of the Connection.php类,我还没有找到beginTransactioncommitrollback方法{ {3}}使用。

我一无所知,然后我问自己“甚至可以在MongoDB中回滚?”,如果在dbal version中找到了答案:

  

MongoDB不使用带有回滚的传统锁定或复杂事务

:(所以我猜这就是为什么ODM中没有beginTransaction或者什么......

但问题仍然存在:如何为我的测试实施某种回滚?

我现在唯一的想法是手动获取我加载的文档的所有ID,然后在tearDown()中删除它们。但是,嗯......它有点糟糕,不是吗?

其他想法??

修改 在我对这个问题的第一次评论之后,关于我想在测试和开发中拥有相同数据库的事实,我想: 为什么不使用单独的测试数据库,其中开发数据库被复制时测试开始了,可以轻松放弃?

这可能是一个更好的主意吗?它实际上对我来说更容易,更安全。你们觉得怎么样?

谢谢:)

2 个答案:

答案 0 :(得分:4)

  

我没有使用两个单独的DB进行开发和测试

这是第一件要解决的问题 - 因为没有测试数据库,运行测试会影响您的开发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);
    }
}

在测试中使用灯具

使用之前的抽象测试类,您可以根据需要编写使用fixture数据的测试 - 或不使用。以下是一个简单的例子。

<?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.
    }

在每次测试之前,将加载您定义的灯具(截断它们影响的集合),给出一致的db状态作为测试的基础。

答案 1 :(得分:2)

在每次测试之前删除MongoDB数据库,然后加载您需要的灯具。这样每个测试都将完全隔离。