liorchamla/symfony-test-helpers

Provides cool tools to make testing over symfony smoothie and great !


README

Providing smooth and fresh helpers for your functional tests!

Contents

  1. Installation
  2. Basic Usage
  3. Details

Installation

composer require liorchamla/symfony-test-helpers

Since it is not a bundle, you don't need any more configuration 👍

Basic Usage

Get everything out of the box by extending Liior\SymfonyTestHelpers\WebTestCase 💪

<?php

namespace Tests\MyCoolFeature;

use Liior\SymfonyTestHelpers\WebTestCase;

class MyCoolTest extends WebTestCase
{
    public function testItAllWorksFine(): void
    {
        $this->get('/');

        $this->assertSee('Hello World!');
    }
}

Details

The library contains several traits and a base class called Liior\SymfonyTestHelpers\WebTestCase. By extending this WebTestCase class, you automatically use all the traits, but you can also use only one or several traits on a normal WebTestCase class.

You can use whatever you see below, out of the box, by extending Liior\SymfonyTestHelpers\WebTestCase

WithClientTrait part 1: No need to initialize a client anymore

With this trait, you get a KernelBrowser (a.k.a. client) out of the box.

<?php

use Liior\SymfonyTestHelpers\Concerns\WithClientTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyCoolTest extends WebTestCase
{
    use WithClientTrait;

    public function testItRuns(): void
    {
        $this->get('/my/route');

        // Asserts that 'Hello World' is in the content of the response
        $this->assertSee('Hello World!');

        // Asserts that 'foobar' is not in the content of the response
        $this->assertNotSee('foobar')
    }
}

WithClientTrait part 2: HTTP methods made easy

With this trait, you get shortcuts for five HTTP methods :

<?php

use Liior\SymfonyTestHelpers\Concerns\WithClientTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyCoolTest extends WebTestCase
{
    use WithClientTrait;

    public function testItRuns()
    {
        $this->get('/');    // equivalent to $this->client->request('GET', '/')
        $this->post('/');   // equivalent to $this->client->request('POST', '/')
        $this->put('/');    // equivalent to $this->client->request('PUT', '/')
        $this->patch('/');  // equivalent to $this->client->request('PATCH', '/')
        $this->delete('/'); // equivalent to $this->client->request('DELETE', '/')
    }
}

WithAuthenticationTrait: Act as an authenticated user with chosen roles

With this trait, you get shortcut methods to act as an authenticated user:

<?php

use Liior\SymfonyTestHelpers\Concerns\WithAuthenticationTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyCoolTest extends WebTestCase
{
    use WithAuthenticationTrait;

    public function testItRuns(): void
    {
        $client = static::createClient();

        // Authenticate with dummy username, don't need the user to exist in the database
        $this->authenticate($client, "fakeUserName", 'my_firewall_name');
        $client->request('GET', '/protected/route');

        // You can pass custom roles for your simulated user
        $this->authenticate($client, "fakeUserName", 'my_firewall_name', ['ROLE_ADMIN']);
        $client->request('GET', '/admin/foo');

        // A shortcut to authenticate as an admin
        $this->authenticateAsAdmin($client, "fakeUserName", 'my_firewall_name');
        $client->request('GET', '/admin/foo');
    }
}

You can also authenticate with a real user !

<?php

use Liior\SymfonyTestHelpers\Concerns\WithAuthenticationTrait;
use Liior\SymfonyTestHelpers\Concerns\WithDatabaseTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Entity\User;

class MyCoolTest extends WebTestCase
{
    use WithAuthenticationTrait;
    use WithDatabaseTrait;

    public function testItRuns(): void
    {
        $client = static::createClient();

        // Create a user (it must be an instance of UserInterface)
        $user = new User;
        $user->setEmail("any@email.com")
            ->setPassword("password")
            ->setRoles(['ROLE_MANAGER', 'ROLE_AUTHOR']);

        // You get this from WithDatabaseTrait
        $this->getManager()->persist($user);
        $this->getManager()->flush();

        // Then you can authenticate with this user
        $this->authenticate($client, $user, "my_firewall_name");
        $client->request('GET', '/protected/route');

        // You can also override roles :
        $this->authenticate($client, $user, "my_firewall_name", ['ROLE_MODERATOR', 'ROLE_ADMIN']);
        $client->request('GET', '/admin/foo');
    }
}

WithDatabaseTrait: Interaction with database made easy

With this trait, you can retrieve Doctrine EntityManager, Repositories and assert that a string is found in a table (experimental)

<?php

use App\Entity\Task;
use Liior\SymfonyTestHelpers\Concerns\WithDatabaseTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyCoolTest extends WebTestCase
{
    use WithDatabaseTrait;

    public function testItRuns(): void
    {
        $client = static::createClient();

        // Retrieve a repository
        $repository = $this->getRepository(Task::class);
        $tasks = $repository->findAll();

        // Retrieve a manager
        $task = new Task();
        $task->setTitle('A task');
        $manager = $this->getManager();
        $manager->persist($task);
        $manager->flush();

        // Shortcut function to create a row inside database (returns the persisted entity)
        $task = $this->createOne(Task::class, function(Task $entity) {
            $entity
                ->setTitle("A task")
                ->setDescription("A description")
                ->setDueDate(new \DateTime())
            ;
        });

        // Shortcut function to create several rows inside database (returns an array of persisted entities)
        $tasks = $this->createMany(Task::class, function(Task $entity, int $index) {
            $entity
                ->setTitle("Task n°$index")
                ->setDescription("Description for task $index")
                ->setDueDate(new \DateTime('+'.$index.' days'))
            ;
        });

        // Experimental! An assertion function which looks up data in a table
        // With a simple string
        $this->assertDatabaseHas('A title', Task::class);

        // With an array of data
        $this->assertDatabaseHas([
            'title' => 'A title',
            'description' => 'A description'
        ], Task::class);

        // With a customized query
        $this->assertDatabaseHas('James', Task::class, function(\Doctrine\ORM\QueryBuilder $qb) {
            $qb->addSelect('a.name')
                ->innerJoin($root. '.author', 'a');
        });

        // Inversed logic : asserts that database is missing 'foo' in Task entity
        $this->assertDatabaseNotHas('foo', Task::class);
    }
}

WithFakerTrait: Using faker made easy

With this trait, you gain access to faker.

<?php

use Faker\Factory;
use Liior\Faker\PricesProvider;
use Liior\SymfonyTestHelpers\Concerns\WithFakerTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyCoolTest extends WebTestCase
{
    use WithFakerTrait;

    // You can choose your locale (default is fr_FR 👍)
    protected $fakerLocale = 'en_GB';

    public function testItRuns()
    {
        // You can use all faker's methods!
        $sentence = $this->fake()->sentence;
        $paragraph = $this->fake()->paragraph;

        // You can also tweak the way Faker's generator is created
        // and set providers as you want.
        $this->initializeFaker(function(){
            $faker = Factory::create('fr_FR');
            $faker->addProvider(new PricesProvider($faker));

            return $faker;
        });
    }
}