[英]Symfony2 Doctrine MongoDB rollback
我正在嘗試使用 Symfony2、Doctrine 和 MongoDB 構建一組安全的測試。
我需要做的是在測試開始時加載很多 fixtures,並在測試結束時卸載它們。 我想用事務來做,但是......我找不到關於如何用 Doctrine 和 Mongo 做的文檔!
我在 Doctrine 文檔中找到了關於如何與 ORM 進行交易的很好的文檔,但沒有關於 ODM 的文檔。
所以我也看了一下Doctrine-Mongo使用的Connection.php
class的源碼,沒有找到dbal版本使用的beginTransaction
、 commit
和rollback
方法。
我一頭霧水,然后我問自己“是否有可能在 MongoDB 回滾?”,如果在MongoDB FAQ中找到答案是:
MongoDB 不使用傳統的鎖定或復雜的交易回滾
:( 所以我想這就是為什么 ODM 中沒有beginTransaction
或任何內容的原因......
但我的問題仍然存在:如何為我的測試實現某種回滾?
我現在唯一的想法是手動獲取我加載的文檔的所有 ID,然后在tearDown()
中刪除它們。 但是,好吧……有點糟糕,不是嗎?
其他想法??
編輯:在我對這個問題發表第一條評論之后,關於我想在測試和開發中擁有相同的數據庫這一事實,我想:為什么不使用單獨的測試數據庫,在測試開始時復制開發數據庫,那可以輕松丟棄嗎?
這會是一個更好的主意嗎? 它實際上對我來說看起來更容易和更安全。 你們有什么感想?
謝謝:)
我沒有使用兩個單獨的數據庫進行開發和測試
這是首先要解決的問題——因為沒有測試數據庫,運行測試將影響您的開發數據庫,反之亦然,這是一個糟糕的主意。 您應該能夠在您的生產環境中運行測試,絕對有信心您在測試中所做的任何事情都不會影響您部署的站點。
設置測試連接
因此,將您的 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%
准備測試夾具
那么,你想要有效地做的是:
在每次測試之前在您的測試數據庫上。
這是一個示例抽象測試 class:
<?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);
}
}
在測試中使用固定裝置
通過前面的抽象測試 class,您可以編寫使用或不使用您的夾具數據的測試,視情況而定。 下面是一個簡單的例子。
<?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.
}
在每次測試之前,您定義的固定裝置將被加載(截斷它們影響的 collections),提供一致的 db state 作為測試的基礎。
只需在每次測試前刪除您的 MongoDB 數據庫,然后加載您需要的設備。 這樣每個測試都將完全隔離。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.