Some useful classes to use when using an in-memory database that has to be resetted on each kernel boot.
<?php
namespace Tests;
use Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;
abstract class WebTestCase extends BaseWebTestCase
{
protected static function bootKernel(array $options = [])
{
parent::bootKernel($options);
static::loadFixtures();
}
/**
* Loads the fixture if possible
*/
private static function loadFixtures()
{
// Here, we create the database each time the kernel is booted.
// This ensures that potential fixtures or entities manipulations don't interact with other tests.
if (is_a(static::class, 'Tests\DatabaseTestInterface', true)) {
$application = new Application(static::$kernel);
// Create database schema.
$schemaCommand = new CreateSchemaDoctrineCommand();
$application->add($schemaCommand);
$schemaCommand->run(new ArrayInput(['command' => 'doctrine:schema:create']), new ConsoleOutput());
// If there are fixtures to insert, let's insert them.
if (is_a(static::class, 'Tests\FixturesTestInterface', true)) {
/** @var string[] $fixtures */
$fixtures = static::getFixturesToInsert();
if (!$fixtures) {
return;
}
// Convert all classes to file names.
foreach ($fixtures as $k => $fixture) {
if (class_exists($fixture)) {
$reflection = new \ReflectionClass($fixture);
$fixtures[$k] = $reflection->getFileName();
}
}
// Load all desired fixtures.
$fixturesCommand = new LoadDataFixturesDoctrineCommand();
$application->add($fixturesCommand);
$fixturesCommand->run(new ArrayInput([
'command' => 'doctrine:fixtures:load',
'--append' => true,
'--fixtures' => $fixtures,
]), new ConsoleOutput());
}
}
}
}
<?php
namespace Tests\Controller;
use AppBundle\Entity\Page;
use Tests\DatabaseTestInterface;
use Tests\WebTestCase;
class PortalControllerTest extends WebTestCase implements DatabaseTestInterface
{
/**
* Nothing in database except db structure (so no error in functional test)
*/
public function testHomepageIndex()
{
$client = static::createClient();
// This is mandatory, else the kernel will drop memory database after a request.
// But this can be added in your WebTestCase class anyway (I personally override this everytime).
$client->disableReboot();
$client->request('GET', '/');
static::assertEquals(404, $client->getResponse()->getStatusCode());
}
/**
* @see GeneratorController::indexAction
*/
public function testIndexWithHomepage()
{
$client = static::createClient();
// This is mandatory, else the kernel will drop memory database after a request.
// But this can be added in your WebTestCase class anyway (I personally override this everytime).
$client->disableReboot();
// Example with OrbitaleCmsBundle:Page entity.
$page = new Page();
$page
->setHomepage(true)
->setHost('localhost')
->setTitle('Homepage test')
->setContent('<h2>This tag is only here for testing</h2>')
->setSlug('homepage-test')
->setLocale('fr')
->setEnabled(true)
;
/** @var EntityManager $em */
$em = static::$kernel->getContainer()->get('doctrine')->getManager();
$em->persist($page);
$em->flush();
$crawler = $client->request('GET', '/');
static::assertEquals(200, $client->getResponse()->getStatusCode(), $client->getResponse()->getContent());
// Test that inserted page corresponds
static::assertEquals($page->getTitle(), trim($crawler->filter('#content section article h1')->html()));
static::assertContains($page->getContent(), trim($crawler->filter('#content section article')->html()));
}
}
<?php
namespace Tests;
/**
* Allows inserting fixtures before kernel boot.
*/
interface FixturesTestInterface extends DatabaseTestInterface
{
/**
* List of all fixtures to run when kernel is booted, with their class names.
*
* @return string[]
*/
public static function getFixturesToInsert();
}
<?php
namespace Tests\Controller;
use AppBundle\DataFixtures\ORM\PageFixtures;
use Tests\FixturesTestInterface;
use Tests\WebTestCase;
class DefaultEasyAdminTest extends WebTestCase implements FixturesTestInterface
{
/**
* Test backend homepage.
*/
public function testIndex()
{
$client = static::createClient();
// This is mandatory, else the kernel will drop memory database after a request.
// But this can be added in your WebTestCase class anyway (I personally override this everytime).
$client->disableReboot();
$client->request('GET', '/admin/');
static::assertEquals(302, $client->getResponse()->getStatusCode(), print_r($client->getResponse()->getContent(), true));
static::assertEquals('/admin/?action=list&entity=Pages', $client->getResponse()->headers->get('Location'));
$crawler = $client->followRedirect();
static::assertEquals(200, $client->getResponse()->getStatusCode(), $crawler->filter('title')->html());
static::assertEquals('EasyAdmin', $crawler->filter('meta[name="generator"]')->attr('content'));
// This makes sure that the admin "list" table contains at least one element.
static::assertGreaterThanOrEqual(1, $crawler->filter('#main.content .table-responsive tbody tr[data-id]')->count());
}
/**
* {@inheritdoc}
*/
public static function getFixturesToInsert()
{
return [
PageFixtures::class,
];
}
}
<?php
namespace Tests;
/**
* This class allows recreating the database when a kernel is booted.
* A database test MUST use the WebTestCase::bootkernel method in every test.
*/
interface DatabaseTestInterface
{
/**
* Boots the Kernel for this test.
*
* @param array $options
*/
public static function bootKernel(array $options = []);
}