11/08/2018 - DOCTRINE, PHPUNIT, SYMFONY
In this example we are going to rollback changes done to data in our database so that we don't have to reload Doctrine DataFixtures for each tests. This will increase test performace becase we load DataFixtures only once at the beginning of the whole test suite and rollback any changes done after each test cases. As a result our tests won't break even though they all depend on same data.
declare(strict_types=1);
namespace App\Tests;
use App\DataFixtures\CountryFixtures;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class AbstractTest extends WebTestCase
{
/** @var Client $client */
protected $client;
/** @var EntityManagerInterface */
private $entityManager;
public static function setUpBeforeClass()
{
$kernel = static::createKernel();
$kernel->boot();
$entityManager = $kernel->getContainer()->get('doctrine')->getManager();
$loader = new Loader();
foreach (self::getFixtures() as $fixture) {
$loader->addFixture($fixture);
}
$purger = new ORMPurger();
$purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
$executor = new ORMExecutor($entityManager, $purger);
$executor->execute($loader->getFixtures());
}
protected function setUp()
{
$this->client = static::createClient();
$this->client->disableReboot();
$this->entityManager = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->entityManager->beginTransaction();
$this->entityManager->getConnection()->setAutoCommit(false);
}
protected function tearDown()
{
if ($this->entityManager->getConnection()->isTransactionActive()) {
$this->entityManager->rollback();
}
}
private static function getFixtures(): iterable
{
return [
new CountryFixtures(),
];
}
}
The update_one
method below actually changes the code
and name
values of Great Britain
record in database. I've just used GET
method to keep this example as short as possible for demonstration purposes. The code
is changed as abc
and name
is changed as Hello
in the background. As you will see in the test result below, the get_all_returns_valid_response_2
didn't break!
declare(strict_types=1);
namespace App\Tests\Controller;
use App\Tests\AbstractTest;
class CountryControllerTest extends AbstractTest
{
/**
* @test
* @dataProvider getAllDataProvider
*/
public function get_all_returns_valid_response_1(int $code, string $body): void
{
$this->client->request('GET', '/api/v1/countries');
$this->assertSame($code, $this->client->getResponse()->getStatusCode());
$this->assertSame($code, $this->client->getResponse()->getStatusCode());
$this->assertSame($body, $this->client->getResponse()->getContent());
}
/**
* @test
*/
public function update_one(): void
{
$this->client->request('GET', '/api/v1/countries/1');
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
}
/**
* @test
* @dataProvider getAllDataProvider
*/
public function get_all_returns_valid_response_2(int $code, string $body): void
{
$this->client->request('GET', '/api/v1/countries');
$this->assertSame($code, $this->client->getResponse()->getStatusCode());
$this->assertSame($body, $this->client->getResponse()->getContent());
}
public function getAllDataProvider(): iterable
{
return [
[
'$code' => 200,
'$body' => <<[
{
"id": 1,
"code": "gb",
"name": "Great Britain",
},
{
"id": 2,
"code": "tr",
"name": "Turkey",
},
{
"id": 3,
"code": "de",
"name": "Germany",
}
]
EOT
]
];
}
}
$ vendor/bin/phpunit --filter CountryControllerTest tests/Controller/CountryControllerTest.php
PHPUnit 7.1.5 by Sebastian Bergmann and contributors.
... 3 / 3 (100%)
Time: 592 ms, Memory: 12.00MB
OK (3 tests, 5 assertions)