Cours Laravel 9 - Les Tests
Cours Laravel 9 - Les Tests
Cours Laravel 9 - Les Tests
26 février 2022
Les développeurs PHP n’ont pas été habitués à faire des tests pour leurs applications. Cela
est dû à l’histoire de ce langage qui n’était au départ qu’une possibilité de scripter au milieu
du code HTML mais qui s’est peu à peu développé comme un langage de plus en plus
évolué. Les créateurs de frameworks ont initié une autre façon d’organiser le code de PHP,
en particulier ils ont mis en avant la séparation des tâches qui a rendu la création de tests
possible.
Laravel a été pensé pour intégrer des tests. Il comporte une infrastructure élémentaire et des
helpers. Nous allons voir dans ce chapitre cet aspect de Laravel. Considérez ce que je vais
vous dire ici comme une simple introduction à ce domaine qui mériterait à lui seul un cours
spécifique. Je vais m’efforcer de vous démontrer l’utilité de créer des tests, comment les
préparer et comment les isoler.
Lorsqu’on développe avec PHP on effectue forcément des tests au moins manuels. Par
exemple si vous créez un formulaire vous allez l’utiliser, entrer diverses informations,
essayer des fausses manœuvres… Imaginez que tout cela soit automatisé et que vous
n’ayez qu’à cliquer pour lancer tous les tests. C’est le propos de ce chapitre.
Vous pouvez aussi vous dire qu’écrire des tests conduit à du travail supplémentaire, que ce
n’est pas toujours facile, que ce n’est pas nécessaire dans tous les cas. C’est à vous de voir
si vous avez besoin d’en créer ou pas. Pour des petites applications la question reste
ouverte. Par contre dès qu’une application prend de l’ampleur ou lorsqu’elle est conduite par
plusieurs personnes alors il devient vite nécessaire de créer des tests automatisés.
L’intendance des tests
PHPUnit
Laravel utilise PHPUnit pour effectuer les tests. C’est un framework créé par Sebastian
Bergmann qui fonctionne à partir d’assertions.
"require-dev": {
...
"phpunit/phpunit": "^9.5.10"
},
https://www.printfriendly.com/p/g/4mKVgX 1/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Mais vous pouvez aussi utiliser le fichier phar que vous pouvez télécharger à partir de cette
page et le placer à la racine de votre application et vous êtes prêt à tester !
php vendor\phpunit\phpunit\phpunit -h
L’intendance de Laravel
Si vous regardez les dossiers de Laravel vous allez en trouver un qui est consacré aux tests
:
<?php
namespace Tests;
use CreatesApplication;
Cette classe est chargée de créer une application pour les tests dans un environnement
spécifique (ce qui permet de mettre en place une configuration adaptée aux tests).
Toutes les classes de test que vous allez créer devront étendre cette classe TestCase.
https://www.printfriendly.com/p/g/4mKVgX 2/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
/**
* @return void
*/
$this->assertTrue(true);
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
/**
* @return void
*/
$response = $this->get('/');
$response->assertStatus(200);
Pourquoi 2 dossiers ?
https://www.printfriendly.com/p/g/4mKVgX 3/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
By default, your application's tests directory contains two directories: Feature and
Unit. Unit tests are tests that focus on a very small, isolated portion of your code.
In fact, most unit tests probably focus on a single method...
Feature tests may test a larger portion of your code, including how several objects
interact with each other or even a full HTTP request to a JSON endpoint.
Generally, most of your tests should be feature tests. These types of tests provide th
En gros dans Feature on va mettre des tests plus généraux, pas vraiment unitaires pour le
coup. Mais vous pouvez utiliser ces deux dossiers à votre convenance et n’en utiliser qu’un
seul.
Sans entrer pour le moment dans le code sachez simplement que dans le premier exemple
on se contente de demander si un truc vrai est effectivement vrai (bon c’est sûr que ça
devrait être vrai ^^). Dans le second on envoie une requête pour la route de base et on
attend une réponse positive (200).
Pour lancer ces tests c’est très simple, entrez la commande php artisan test :
On voit qu’ont été effectués 2 tests et 2 assertions et que tout s’est bien passé.
L’environnement de test
Je vous ai dit que les tests s’effectuent dans un environnement particulier, ce qui est bien
pratique.
https://www.printfriendly.com/p/g/4mKVgX 4/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<php>
</php>
</phpunit>
On peut évidemment ajouter les variables dont on a besoin. Par exemple si pendant les
tests je ne veux plus MySql mais sqlite.
https://www.printfriendly.com/p/g/4mKVgX 5/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
DB_CONNECTION=mysql
Construire un test
Comme tout ça est un peu abstrait prenons un exemple. Remplacez le code avec celui-ci
(peu importe dans quel dossier) :
$result = array_sum($data);
$this->assertEquals(60, $result);
Supprimez le test dans l’autre dossier pour éviter de polluer les résultats.
$result = array_sum($data);
On teste le résultat :
$this->assertEquals(60, $result);
Vous voyez à nouveau l’exécution d’un test. Le tout s’est bien passé. Changez la valeur 60
par une autre et vous obtiendrez ceci :
https://www.printfriendly.com/p/g/4mKVgX 6/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Vous connaissez maintenant le principe de base d’un test et ce qu’on peut obtenir comme
renseignement en cas d’échec.
Les assertions
Les assertions constituent l’outil de base des tests. On en a vu une ci-dessus et il en existe
bien d’autres. Vous pouvez en trouver la liste complète ici.
Voici quelques assertions et l’utilisation d’un helper de Laravel que l’on teste au passage :
https://www.printfriendly.com/p/g/4mKVgX 7/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
use Illuminate\Support\Str;
...
$this->assertTrue(Str::startsWith($data, 'Je'));
$this->assertFalse(Str::startsWith($data, 'Tu'));
$this->assertStringStartsWith('Je', $data);
$this->assertStringEndsWith('petit', $data);
Il est facile d’appeler une route pour effectuer un test sur la réponse. Modifiez la route de
base pour celle-ci :
Route::get('/', function () {
return 'coucou';
});
On a donc une requête avec l’url de base et comme réponse la chaîne coucou. Nous allons
tester que la requête aboutit bien, qu’il y a une réponse correcte et que la réponse est
coucou (effectuez ce test dans le dossier Feature) :
$response = $this->get('/');
$response->assertSuccessful();
$this->assertEquals('coucou', $response->getContent());
L’assertion assertSuccessful nous assure que la réponse est correcte. Ce n’est pas une
assertion de PHPUnit mais une spécifique de Laravel. Vous trouvez toutes les assertion de
Laravel ici.
https://www.printfriendly.com/p/g/4mKVgX 8/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Les vues
Qu’en est-il si on retourne une vue ?
Route::get('/', function () {
});
{{ $message }}
$response = $this->get('/');
https://www.printfriendly.com/p/g/4mKVgX 9/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Les contrôleurs
Créez ce contrôleur :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
return view('welcome');
use App\Http\Controllers\WelcomeController;
Vérifiez que ça fonctionne (vous aurez peut-être besoin de retoucher la vue où nous avons
introduit une variable).
https://www.printfriendly.com/p/g/4mKVgX 10/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
/**
* @return void
*/
$response = $this->get('/');
$response->assertStatus(200);
$response = $this->get('welcome');
$response->assertStatus(200);
Pour faire des tests efficaces il faut bien les isoler, donc savoir ce qu’on teste, ne tester
qu’une chose à la fois et ne pas mélanger les choses.
https://www.printfriendly.com/p/g/4mKVgX 11/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Ceci est possible si le code est bien organisé, ce que je me suis efforcé de vous montrer
depuis le début de ce cours.
Avec PHPUnit chaque test est effectué dans une application spécifique, il n’est donc pas
possible de les rendre dépendants les uns des autres.
"require-dev": {
...,
"mockery/mockery": "^1.4.4",
...
"phpunit/phpunit": "^9.5.10"
},
Nous allons voir maintenant comment l’utiliser mais pour cela on va mettre en place le code
à tester. Ce ne sera pas trop réaliste mais c’est juste pour comprendre le mécanisme de
fonctionnement de Mockery. Remplacez le code du contrôleur WelcomeController par
celui-ci :
https://www.printfriendly.com/p/g/4mKVgX 12/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
<?php
namespace App\Http\Controllers;
use App\Services\Livre;
$this->middleware('guest');
$titre = $livre->getTitle();
J’ai prévu l’injection d’une classe dans la méthode index. Voilà la classe en question :
<?php
namespace App\Services;
class Livre
return 'Titre';
Bon d’accord ce n’est pas très joli mais c’est juste pour la démonstration…
La difficulté ici réside dans la présence de l’injection d’une classe. Comme on veut isoler les
tests, l’idéal serait de pouvoir simuler cette classe. C’est justement ce que permet de faire
Mockery.
https://www.printfriendly.com/p/g/4mKVgX 13/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Services\Livre;
// Création Mock
$mock->shouldReceive('getTitle')->andReturn('Titre');
});
// Action
$response = $this->get('welcome');
// Assertions
$response->assertSuccessful();
$response->assertViewHas('titre', 'Titre');
{{ $titre }}
Voyons de plus près ce code… On crée un objet Mock en lui demandant de simuler la
classe Livre :
$this->mock(Livre::class, function ($mock) {
->shouldReceive('getTitle')->andReturn('Titre');
On lui dit qu’il reçoit (shouldReceive) l’appel de la méthode getTitle et doit retourner Titre.
$response = $this->get('welcome');
Pour finir on prévoit deux assertions, une pour vérifier qu’on a une réponse correcte et la
seconde pour vérifier qu’on a bien le titre dans la vue :
$response->assertSuccessful();
$response->assertViewHas('titre', 'Titre');
https://www.printfriendly.com/p/g/4mKVgX 14/15
9/17/22, 11:27 PM Cours Laravel 9 – les tests
Il n’y a pas vraiment de règle quant à la constitution des tests, quant à ce qu’il faut tester ou
pas. L’important est de comprendre comment les faire et de juger ce qui est utile ou pas
selon les circonstances. Une façon efficace d’apprendre à réaliser des tests tout en
comprenant mieux Laravel est de regarder comment ses tests ont été conçus.
En résumé
Laravel utilise PHPUnit pour effectuer les tests unitaires.
En plus des méthodes de PHPUnit on dispose d’helpers pour intégrer les tests dans
une application réalisée avec Laravel.
Le composant Mockery permet de simuler le comportement d’une classe et donc de
bien isoler les tests.
https://www.printfriendly.com/p/g/4mKVgX 15/15