FabRiviere / Livre_Or_Symfony

Développement du projet concernant un livre d'or sur les conférences. Projet du livre Symfony 6.
0 stars 0 forks source link

Réalisation des tests #35

Closed FabRiviere closed 1 year ago

FabRiviere commented 1 year ago
FabRiviere commented 1 year ago

Installation du package PHPUnit :

symfony composer req phpunit --dev

Générer un test unitaire pour SpamChecker :

symfony console make:test TestCase SpamCheckerTest

Création du test lors de renvoi d'une erreur par l'api Akismet :

<?php

namespace App\Tests;

use App\Entity\Comment;
use App\Service\SpamChecker;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;

class SpamCheckerTest extends TestCase
{
    public function testSpamScoreWithInvalidRequest(): void
    {
        $comment = new Comment();
        $comment->setCreatedAtValue();
        $context = [];
        // ! La classe MockHttpClient permet de simuler un serveur HTTP.On lui donne un tableau d'instance MockResponse contenant le corps et en-têtes de réponse attendus.
        $client = new MockHttpClient([new MockResponse('invalid', ['response_headers' => ['x-alismet-debug-help: Invalid key']])]);
        $checker = new SpamChecker($client, 'abcde');

        // ! Appel de la méthode getSpamScore et vérifiaction qu'une exception est levée via la méthode expectException de PHPUnit. 
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage('Unable to check for spam : invalid (Invalid key).');
        $checker->getSpamScore($comment, $context);
    }
}

Création du test lors de renvoi de succès :

// ! Les data providers de PHPUnit permettent de réutiliser la même logique pr plusieurs scénarios

 /**
     * @dataProvider provideComments
     */
    public function testSpamScore(int $expectedScore, ResponseInterface $response, Comment $comment, array $context)
    {
        $client = new MockHttpClient([$response]);
        $checker = new SpamChecker($client, 'abcde');

        $score = $checker->getSpamScore($comment, $context);
        $this->assertSame($expectedScore, $score);
    }

    public static function provideComments(): iterable
    {
        $comment = new Comment();
        $comment->setCreatedAtValue();
        $context = [];

        $response = new MockResponse('', ['response_headers' => ['x-akismet-pro-tip: discard']]);
        yield 'blatant_spam' => [2, $response, $comment, $context];

        $response = new MockResponse('true');
        yield 'spam' => [1, $response, $comment, $context];

        $response = new MockResponse('false');
        yield 'ham' => [0, $response, $comment, $context];
    }

Créations des tests fonctionnels pour les contrôleurs :

Création d'un dossier Controller dans le dossier tests et nouveau fichier ConferenceControllerTest.php

<?php

namespace App\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class ConferenceControllerTest extends WebTestCase
{
    public function testIndex()
    {
        $client = static::createClient();
        $client->request('GET', '/');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('h2', 'Give your feedback');
    }
}

Configuration de l'environnement de tests :

symfony console secrets:set AKISMET_KEY --env=test

On tape ensuite notre clé d'API Akismet.

Initialisation de la base de données test :

symfony console doctrine:database:create --env=test

symfony console doctrine:migrations:migrate -n --env=test

Définir et écriture des fixtures :

Installation du package Doctrine Fixtures :

symfony composer req orm-fixtures --dev

Modification du fichier AppFixtures.php généré par le package

<?php

namespace App\DataFixtures;

use App\Entity\Admin;
use App\Entity\Comment;
use App\Entity\Conference;
use Doctrine\Persistence\ObjectManager;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;

class AppFixtures extends Fixture
{
    public function __construct(private PasswordHasherFactoryInterface $passwordHasherFactory)
    {

    }

    public function load(ObjectManager $manager): void
    {
        $amsterdam = new Conference();
        $amsterdam->setCity('Amsterdam');
        $amsterdam->setYear('2019');
        $amsterdam->setIsInternational(true);
        $manager->persist($amsterdam);

        $paris = new Conference();
        $paris->setCity('Paris');
        $paris->setYear('2020');
        $paris->setIsInternational(false);
        $manager->persist($paris);

        $comment1 = new Comment();
        $comment1->setConference($amsterdam);
        $comment1->setAuthor('Fabien');
        $comment1->setEmail('fabien@example.com');
        $comment1->setText('This is a great conference.');
        $manager->persist($comment1);

        $admin = new Admin();
        $admin->setRoles(['ROLE_ADMIN']);
        $admin->setUsername('Fabsolo');
        $admin->setEmail('fabsolo@email.fr');
        $admin->setPassword($this->passwordHasherFactory->getPasswordHasher(Admin::class)->hash('azerty'));
        $admin->setFirstname('Fab');
        $admin->setLastname('Solo');
        $admin->setIsVerified(1);
        $manager->persist($admin);

        $manager->flush();
    }
}

Chargement des données de test :

symfony console doctrine:fixtures:load --env=test

Création du test fonctionnel pour le click sur une conférence en page d'accueil :

Ajout d'une méthode dans le ConferenceControllerTest.php

public function testConferencePage()
    {
        $client = static::createClient();
        // ! On retourne 1 instance de crawler qui aide à trouver des éléments sur la page.
        $crawler = $client->request('GET', '/');
        // ! On vérifie qu'on a bien 2 conférences listées sur la page.
        $this->assertCount(2, $crawler->filter('h4'));

        // ! On clique sur le view -> le premier qu'il trouve.
        $client->clickLink('View');

        // ! On vérifie le titre de la page et que la réponse est le h2 pour être sur d'être sur la bonne page.
        $this->assertPageTitleContains('Amsterdam');
        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('h2', 'Amsterdam 2019');

        // ! On vérife qu'il y a 1 commentaire sur la page.
        $this->assertSelectorExists('div:contains("There are 1 comments")');
    }

On peut ensuite vérifier que le nouveau test passe :

symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php

Création du test fonctionnel pour la soumission du formulaire de commentaire :

Ajout d'une méthode dans le ConferenceControllerTest.php

public function testCommentSubmission()
    {
        $client = static::createClient();
        $client->request('GET', '/conference/amsterdam-2019');
        $client->submitForm('Submit', [
            'comment_form[author]' => 'Fabien',
            'comment_form[text]' => 'Some feedback from an automated functional test',
            'comment_form[email]' => 'me@automat.ed',
            'comment_form[photo]' => dirname(__DIR__, 2). '/public/images/under-construction.gif',
        ]);
        $this->assertResponseRedirects();
        $client->followRedirect();
        $this->assertSelectorExists('div:contains("There are 2 comments")');
    }

On peut ensuite vérifier que le nouveau test passe :

symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php