我正在尝试使用 Symfony2、Doctrine 和 MongoDB 构建一组安全的测试。
我需要做的是在测试开始时加载大量夹具,并在测试结束时卸载它们。我想用transaction来做,但是...我找不到关于如何用 Doctrine 和 Mongo 做的文档!
我找到了 good documentation在 Doctrine 文档中关于如何与 ORM 进行交易,而不是关于 ODM。
所以我看了一下 source code of the Connection.php
Doctrine-Mongo 也使用了类,我还没有找到 dbal version 的 beginTransaction
、commit
和 rollback
方法用途。
我一无所知,然后我问自己“是否有可能在 MongoDB 中回滚?”,如果在 MongoDB FAQ 中找到答案。是:
MongoDB does not use traditional locking or complex transactions with rollback
:( 所以我想这就是为什么在 ODM 中没有 beginTransaction
或其他任何东西...
但我的问题仍然存在:如何为我的测试实现某种回滚?
我现在唯一的想法是手动获取我加载的文档的所有 id,然后在 tearDown()
中删除它们。但是,嗯……这有点糟糕,不是吗?
其他想法??
编辑: 在我对这个问题的第一次评论之后,关于我希望在测试和开发中拥有相同的数据库这一事实,我想:为什么不使用单独的测试数据库,开发数据库在什么时候被复制测试开始了,可以轻松放弃吗?
这是一个更好的主意吗?它实际上对我来说看起来更容易,更安全。大家觉得呢?
谢谢:)
最佳答案
I am not using two separate DBs for development and testing
这是首先要解决的问题 - 因为没有测试数据库,运行测试会影响您的开发数据库反之亦然,这是一个糟糕的主意。您应该能够在生产环境中运行测试,并且绝对确信您在测试中所做的任何事情都不会影响您部署的站点。
设置测试连接
所以,修改你的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.
}
在每次测试之前,您定义的固定装置将被加载(截断它们影响的集合),从而提供一致的数据库状态作为测试的基础。
关于php - Symfony2 Doctrine MongoDB 回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10012779/