I'm trying to write a functional test for my project in Symfony2. I'd like to test if a user can access a page, fill up a form and submit it. I'm tryingto find a way to rollback the database to the state it was before the test. I found a helper class I slighty modified at https://gist.github.com/Vp3n/5472509 wich extends WebTestCase and overload setUp and tearDown methods. Here are the mods I did in order to try to make it works:
/**
* 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();
}
}
When I run the tests, it acknowledges for existing transactions but the rollback fails and modifications are persisted.
Test Logs:
Runtime: PHP 5.6.15
.existing transactions. 2/2 (100%)existing transactions
Time: 5.47 seconds, Memory: 24.50MB
OK (2 tests, 5 assertions)
What am I doing wrong ? Is that even the best practice ? Any help would be appreciated :)
EDIT
This worked for me:
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();
}
}
}
Are you doing more than one request with the
Client
? If so, you problem might be that the client shutdowns the kernel after one request was performed. But you can disable that with$this->client->disableReboot()
So this snippet snippet should be idempotent:I would recommend to use this bundle: https://packagist.org/packages/dama/doctrine-test-bundle
Its very easy to setup and will roll-back any database changes automatically after every single testcase. No need to implement any custom things.
You could use a dedication test database for testing
Another option is using Codeception. This is a unit testing bundle that works with Symfony. If you use this, you can configure it to use a test database and then "clean it up" after each testing cycle.
An example yaml configuartion to do that would be something like, it is the
cleanup: true
that does what you want;