05 Test unitaire & d'intégration
Vous pouvez reprendre le contenu de votre TP2 pour ce TP, peut être même un fork de votre dépôt ? 😉
Et les tests dans tout ça ?
Déjà un TD sur les tests unitaires et d'intégrations ? Si tôt dans la découverte du module ?
Et oui ! C'est bien beau de parler de TDD mais encore faut il le mettre en place et savoir en faire.
Plutôt que de tout tester à la main de maniére répétitif et fastidieuse, nous allons apprendre à les automatiser pour notre plus grand bonheur 😀.
Pré-requis
Pour réaliser les tests unitaires et d'intégrations nous aurons besoin des librairies php suivantes:
- phpunit/phpunit
- guzzlehttp/guzzle
- symfony/process
Un petit composer require
pour l'installation ?
Structure de notre dossier
En reprenant la structure de votre TP2 vous devriez avoir:
-- src/
-- vendor/
-- index.php
-- composer.json
-- composer.lock
Nous allons donc créer un répertoire tests
à la racine de notre projet qui contiendra nos fichier de tests.
Premier test unitaire
L'exemple le plus simple pour comprendre le principe des tests unitaires est la fonction de multiplication.
Pour rappel une multiplication est l'opération mathématique permettant d'obtenir le produit de deux facteur (nommés facteur gauche et facteur droite).
Mise en place
- Créer un fichier (vide)
functions.php
dans le répertoiresrc/
- Créer dans le répertoire
tests/
un fichierUnitariesTest.php
- Pensez à modifier votre composer.json pour charger automatiquement le fichier de fonctions qui se trouve dans le répertoire
src/
PHPUnit
PHPUnit est un framework open source de tests unitaires dédié au langage de programmation PHP.
Il permet l'implémentation des tests de régression en vérifiant que les exécutions correspondent aux assertions prédéfinies.
Premier test
Modifier le fichier UnitariesTest.php
pour que son contenu soit:
<?php
require_once 'vendor/autoload.php';
use PHPUnit\Framework\TestCase;
class UnitariesTest extends TestCase {
public function test_multiply(){
$this->assertEquals(4, multiply(2, 2));
}
}
Nous venons de définir une classe de tests qui posséde un fonction permettant de tester notre fonction de multiplication (notez la présence du require
pour charger l'autoloader de composer).
La ligne 9 permet de vérifier que la fonction retourne bien le produit de 2 par 2 (à savoir 4).
Nous avons définit notre premier test, il serait donc temps de le lancer via la commmande suivante:
$ vendor/bin/phpunit tests/UnitariesTest.php
Normalement vous devriez avoir l'erreur suivante :
PHPUnit 7.5.2 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 15 ms, Memory: 4.00MB
There was 1 error:
1) MultiplyTest::test_multiply
Error: Call to undefined function multiply()
/home/sam/php/tests/UnitariesTest.php:8
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
C'est normal ! Nous respectons la philosophie TDD à savoir écrire nos tests d'abord puis vérifier que ceux-ci échouent !
Il convient de créer maintenant notre fonction de multiplication, copier-coller dans votre fichier functions.php
le code (sans erreur) suivant:
<?php
function multiply($facteur_gauche, $facteur_droite)
{
return $facteur_gauche + $facteur_droite;
}
Relancez votre test via la commmande suivante:
$ vendor/bin/phpunit tests/UnitariesTest.php
Notre test passe ! Mais notre jeu de données n'est pas complet ! Il convient donc d'ajouter une assertion supplémentaire à notre test.
- Ajoutez l'assertion que le produit de 3 par 7 est 21
- Relancez votre test que constatez vous ?
- Corrigez le code de votre fonction pour régler ce souci.
Bravo vous venez de faire votre première suite de test unitaire 🎉.
Remarque
Le répertoire
tests
ainsi que le fait de suffixer nos fichier parTest.php
est une convention qui permet à php unit de charger de manière automatique l'ensemble des tests du répertoire.
Il suffit de lancer la commande suivante pour lancer l'ensemble des tests du répertoire tests/
:
$ vendor/bin/phpunit tests/
Test d'intégration
Tester nos fonctions c'est bien, utile et indispensable. Toutefois il est tout aussi indispensable de tester le retour de nos pages, nous allons donc voir comment mettre en place des tests d'intégrations.
Création d'un client de test
Pour pouvoir tester notre site en intégration il convient de créer un client de tests. Votre professeur étant fort sympatique en voici un à placer dans le fichier src/utils.php
<?php
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;
use GuzzleHttp\Client;
abstract class IntegrationTestCase extends TestCase {
private static $process;
public static function setUpBeforeClass(): void
{
self::$process = new Process(["php", "-S", "localhost:8080", "-t", "."]);
self::$process->start();
usleep(100000); //wait for server to get going
}
public static function tearDownAfterClass(): void
{
self::$process->stop();
}
public function get_client()
{
return new Client(['http_errors' => false]);
}
public function build_url($url)
{
return "localhost:8080" . $url;
}
public function make_request($method, $url)
{
$client = $this->get_client();
return $client->request($method, $this->build_url($url));
}
}
Ce client lance en processus votre site web et permet de tester le retour de requête HTTP sur celui-ci.
Notre premier test d'intégration
Créer un fichier IntegrationsTest.php
dans le répertoire tests/
avec le contenu suivant:
<?php
require_once 'vendor/autoload.php';
class PagesIntegrationTest extends IntegrationTestCase{
public function test_index()
{
$response = $this->make_request("GET", "/");
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals("Hello World!", $response->getBody()->getContents());
$this->assertContains("text/html", $response->getHeader('Content-Type')[0]);
}
}
Le test d'intégration test_index
permet de:
- Tester si le retour de la requête sur
/
en méthode GET retourne le code de statut 200, - Et que le contenu de la réponse est bien
Hello World!
. -
Et que le type de contenu est bien du
text/html
. -
Lancez la suite de tests,
- Que constatez vous ?
- Comment corriger le problème ?
Vous savez désormais tester en intégration une page de votre site web.
Un test un peu plus complexe
- Comment mettre en place un test d'intégration pour la route
hello
de votre site ? Pensez à l'esprit TDD et comment tester cela. - Et si notre route
hello
retourner une string sous la forme<h2>Hello $name </h2>
? - Et si on utiliser l'assertion
assertContains
?