使用 Symfony2 进行功能测试时如何回滚事务
How to rollback transactions when doing functional testing with Symfony2
我正尝试在 Symfony2 中为我的项目编写功能测试。我想测试用户是否可以访问页面、填写表格并提交。
我试图找到一种方法将数据库回滚到测试前的状态。
我找到了一个助手 class,我在 https://gist.github.com/Vp3n/5472509 处稍作修改,它扩展了 WebTestCase 并重载了 setUp 和 tearDown 方法。
以下是我为使其正常工作所做的模组:
/**
* Before each test we start a new transaction
* everything done in the test will be canceled ensuring isolation et speed
*/
protected function setUp()
{
parent::setUp();
$this->client = $this->createClient();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
$this->em->getConnection()->beginTransaction();
$this->em->getConnection()->setAutoCommit(false);
}
/**
* After each test, a rollback reset the state of
* the database
*/
protected function tearDown()
{
parent::tearDown();
if($this->em->getConnection()->isTransactionActive()){
echo 'existing transactions';
$this->em->getConnection()->rollback();
$this->em->close();
}
}
当我 运行 测试时,它确认现有事务但回滚失败并保留修改。
测试日志:
Runtime: PHP 5.6.15
.existing transactions. 2/2 (100%)existing transactions
Time: 5.47 seconds, Memory: 24.50MB
OK (2 tests, 5 assertions)
我做错了什么?这甚至是最佳做法吗?
编辑
这对我有用:
abstract class DatabaseWebTest extends WebTestCase {
/**
* helper to acccess EntityManager
*/
protected $em;
/**
* Helper to access test Client
*/
protected $client;
/**
* Before each test we start a new transaction
* everything done in the test will be canceled ensuring isolation et speed
*/
protected function setUp()
{
parent::setUp();
$this->client = $this->createClient(['environment' => 'test'], array(
'PHP_AUTH_USER' => 'user',
'PHP_AUTH_PW' => 'password',
));
$this->client->disableReboot();
$this->em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->em->beginTransaction();
$this->em->getConnection()->setAutoCommit(false);
}
/**
* After each test, a rollback reset the state of
* the database
*/
protected function tearDown()
{
parent::tearDown();
if($this->em->getConnection()->isTransactionActive()) {
$this->em->rollback();
}
}
}
您可以使用专用测试数据库进行测试
另一个选项是使用 Codeception。这是一个与 Symfony 一起工作的单元测试包。
如果您使用它,您可以将其配置为使用测试数据库,然后在每个测试周期后 "clean it up"。
一个 yaml 配置的例子是这样的,cleanup: true
做你想做的事;
class_name: UnitTester
modules:
enabled:
- Asserts
- Symfony2:
app_path: '../../app'
var_path: '../../app'
environment: 'test'
- Doctrine2:
depends: Symfony2
cleanup: true
- \AppBundle\Helper\Unit
您是否使用 Client
执行多个请求?如果是这样,您的问题可能是客户端在执行一个请求后关闭了内核。但是你可以用 $this->client->disableReboot()
禁用它所以这个片段片段应该是幂等的:
public function setUp()
{
$this->client = $this->createClient(['environment' => 'test']);
$this->client->disableReboot();
$this->em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->em->beginTransaction();
}
public function tearDown()
{
$this->em->rollback();
}
public function testCreateNewEntity()
{
$this->client->request('GET', '/create/entity/form');
$this->client->request('POST', '/create/entity/unique/123');
}
我会推荐使用这个包:https://packagist.org/packages/dama/doctrine-test-bundle
它的设置非常简单,并且会在每个测试用例之后自动回滚任何数据库更改。无需实现任何自定义内容。
我正尝试在 Symfony2 中为我的项目编写功能测试。我想测试用户是否可以访问页面、填写表格并提交。 我试图找到一种方法将数据库回滚到测试前的状态。 我找到了一个助手 class,我在 https://gist.github.com/Vp3n/5472509 处稍作修改,它扩展了 WebTestCase 并重载了 setUp 和 tearDown 方法。 以下是我为使其正常工作所做的模组:
/**
* Before each test we start a new transaction
* everything done in the test will be canceled ensuring isolation et speed
*/
protected function setUp()
{
parent::setUp();
$this->client = $this->createClient();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
$this->em->getConnection()->beginTransaction();
$this->em->getConnection()->setAutoCommit(false);
}
/**
* After each test, a rollback reset the state of
* the database
*/
protected function tearDown()
{
parent::tearDown();
if($this->em->getConnection()->isTransactionActive()){
echo 'existing transactions';
$this->em->getConnection()->rollback();
$this->em->close();
}
}
当我 运行 测试时,它确认现有事务但回滚失败并保留修改。
测试日志:
Runtime: PHP 5.6.15
.existing transactions. 2/2 (100%)existing transactions
Time: 5.47 seconds, Memory: 24.50MB
OK (2 tests, 5 assertions)
我做错了什么?这甚至是最佳做法吗?
编辑
这对我有用:
abstract class DatabaseWebTest extends WebTestCase {
/**
* helper to acccess EntityManager
*/
protected $em;
/**
* Helper to access test Client
*/
protected $client;
/**
* Before each test we start a new transaction
* everything done in the test will be canceled ensuring isolation et speed
*/
protected function setUp()
{
parent::setUp();
$this->client = $this->createClient(['environment' => 'test'], array(
'PHP_AUTH_USER' => 'user',
'PHP_AUTH_PW' => 'password',
));
$this->client->disableReboot();
$this->em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->em->beginTransaction();
$this->em->getConnection()->setAutoCommit(false);
}
/**
* After each test, a rollback reset the state of
* the database
*/
protected function tearDown()
{
parent::tearDown();
if($this->em->getConnection()->isTransactionActive()) {
$this->em->rollback();
}
}
}
您可以使用专用测试数据库进行测试
另一个选项是使用 Codeception。这是一个与 Symfony 一起工作的单元测试包。
如果您使用它,您可以将其配置为使用测试数据库,然后在每个测试周期后 "clean it up"。
一个 yaml 配置的例子是这样的,cleanup: true
做你想做的事;
class_name: UnitTester
modules:
enabled:
- Asserts
- Symfony2:
app_path: '../../app'
var_path: '../../app'
environment: 'test'
- Doctrine2:
depends: Symfony2
cleanup: true
- \AppBundle\Helper\Unit
您是否使用 Client
执行多个请求?如果是这样,您的问题可能是客户端在执行一个请求后关闭了内核。但是你可以用 $this->client->disableReboot()
禁用它所以这个片段片段应该是幂等的:
public function setUp()
{
$this->client = $this->createClient(['environment' => 'test']);
$this->client->disableReboot();
$this->em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->em->beginTransaction();
}
public function tearDown()
{
$this->em->rollback();
}
public function testCreateNewEntity()
{
$this->client->request('GET', '/create/entity/form');
$this->client->request('POST', '/create/entity/unique/123');
}
我会推荐使用这个包:https://packagist.org/packages/dama/doctrine-test-bundle
它的设置非常简单,并且会在每个测试用例之后自动回滚任何数据库更改。无需实现任何自定义内容。