使用Symfony2进行功能测试时如何回滚事务

时间:2017-02-17 10:29:24

标签: symfony testing transactions doctrine rollback

我试图在Symfony2中为我的项目编写功能测试。我想测试用户是否可以访问页面,填写表单并提交。 我试图找到一种方法将数据库回滚到测试之前的状态。 我找到了一个帮助类,我在https://gist.github.com/Vp3n/5472509稍微修改了它,扩展了WebTestCase并重载了setUp和tearDown方法。 以下是我为了尝试使其工作所做的mod:

 /**
 * 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();
    }        
}

}

3 个答案:

答案 0 :(得分:7)

您是否使用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');
}

答案 1 :(得分:4)

我建议使用此捆绑包:https://packagist.org/packages/dama/doctrine-test-bundle

它非常容易设置,并且会在每个测试用例后自动回滚任何数据库更改。无需实现任何自定义的东西。

答案 2 :(得分:2)

您可以使用奉献测试数据库进行测试

另一种选择是使用Codeception。这是一个与Symfony一起使用的单元测试包。 如果您使用它,您可以将其配置为使用测试数据库,然后在每个测试周期后“清理”它 举例来说,yaml configuartion就是这样的,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