CI - Tests unitaires đ§Șâïž
LâexĂ©cution de tests unitaires et dâintĂ©grations est au coeur de la dĂ©marche DevOps et dâintĂ©gration continue. Câest eux qui vont permettre de dĂ©tecter les anomalies dans les dĂ©veloppements rĂ©alisĂ©s. Github Actions, si un ou plusieurs tests sont en erreur, va fournir les rapports dĂ©taillĂ©s permettant dâidentifier lâorigine de lâerreur, et va signaler que la tĂąche est en erreur. Cela peut par exemple empĂȘcher un merge de se rĂ©aliser dans Github.
- name: Run tests with coverage
env:
XDEBUG_MODE: coverage
run: php artisan test --coverage --min=80
đŻ Objectifs pĂ©dagogiques
- Comprendre la structure des tests Unit et Feature dans Laravel.
- Ăcrire, exĂ©cuter et interprĂ©ter des tests automatisĂ©s.
- IntĂ©grer les tests dans une pipeline dâintĂ©gration continue (CI).
- Mesurer la couverture de code et fixer un seuil minimal de qualité.
1. Initialisation de lâenvironnement de test đïžâïž
Crée un environnement dédié aux tests.
cp .env .env.testing
php artisan key:generate
â¶ïž Configure .env.testing âïž
D'abord la base de données de Test :
CREATE DATABASE todo_test;
CREATE USER 'laravel_test'@'localhost' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON todo_test.* TO 'laravel_test'@'localhost';
FLUSH PRIVILEGES;
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todo_test
DB_USERNAME=laravel_test
DB_PASSWORD=secret
Fix problĂšm đȘČ sqlite
Par dĂ©faut, Laravel utilise SQLite pour lâexĂ©cution des tests. Cette base, entiĂšrement en mĂ©moire, est trĂšs performante et particuliĂšrement adaptĂ©e aux tests unitaires. Cependant, SQLite gĂšre mal certaines fonctionnalitĂ©s avancĂ©es, notamment les clĂ©s primaires composites que nous avons mises en place dans nos migrations.
Pour garantir un comportement cohĂ©rent entre l'environnement de dĂ©veloppement, l'environnement de test et l'environnement de production, nous faisons donc le choix dâutiliser MySQL Ă©galement pour les tests.
Dans la continuitĂ©, nous provisionnerons un service MySQL via Docker au sein de GitHub Actions afin dâexĂ©cuter automatiquement la suite de tests dans un environnement reproductible et compatible avec nos contraintes de schĂ©ma.
dans le fichier phpunit.xml Ă la racine du projet
<!--
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
-->
<server name="DB_CONNECTION" value="mysql"/>
<server name="DB_DATABASE" value="todo_test"/>
<server name="DB_USERNAME" value="laravel_test"/>
<server name="DB_PASSWORD" value="secret"/>
2. Premier test âSmoke testâ đ§©âïž
CrĂ©e un test pour vĂ©rifier que la page dâaccueil est accessible.
php artisan make:test AccueilTest
Cela créé un nouveau répertoire tests, modifions à présent tests/Feature/AccueilTest.php :
<?php
public function test_invite_est_redirige_depuis_accueil_vers_login()
{
$response = $this->get('/');
$response->assertRedirect(route('login'));
}
public function test_utilisateur_auth_peut_acceder_a_l_accueil()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->followingRedirects()
->get('/');
$response->assertOk();
// On vérifiera qu'on voit bien le texte "Ma Todo List" dans la page
$response->assertSee('Ma Todo List');
}
assertRedirect(route('login'))montre le comportement pour un invitĂ©.actingAs($user)+followingRedirects()illustre le scĂ©nario dâun utilisateur authentifiĂ©.- Lâassertion porte sur un texte rĂ©el de la vue, pas sur le nom de la route.
đ Lançons les tests :
php artisan test
Fix problĂ©m đȘČ
- Mettre en commentaire le contenu de exampleTest.php
- Réparer le test d'authentification
FAILED Tests\Feature\Auth\AuthenticationTest > users can authenticate using the login screen
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'http://localhost/dashboard'
+'http://localhost'
+++ Actual
@@ @@
-'http://localhost/dashboard'
+'http://localhost'
@@ @@
-'http://localhost/dashboard'
+'http://localhost'
-'http://localhost/dashboard'
+'http://localhost'
+'http://localhost'
résultats
(base) PS C:\wamp64\www\todo2026> php artisan test
PASS Tests\Unit\ExampleTest
â that true is true 0.02s
PASS Tests\Feature\AccueilTest
â invite est redirige depuis accueil vers login 0.63s
â utilisateur auth peut acceder a l accueil 0.58s
PASS Tests\Feature\Auth\AuthenticationTest
â login screen can be rendered 3.22s
â users can authenticate using the login screen 0.17s
â users can not authenticate with invalid password 0.29s
â users can logout 0.10s
PASS Tests\Feature\Auth\EmailVerificationTest
â email verification screen can be rendered 0.14s
â email can be verified 0.08s
â email is not verified with invalid hash 0.10s
PASS Tests\Feature\Auth\PasswordConfirmationTest
â confirm password screen can be rendered 0.12s
â password can be confirmed 0.07s
â password is not confirmed with invalid password 0.30s
PASS Tests\Feature\Auth\PasswordResetTest
â reset password link screen can be rendered 0.07s
â reset password link can be requested 0.27s
â reset password screen can be rendered 0.38s
â password can be reset with valid token 0.33s
PASS Tests\Feature\Auth\PasswordUpdateTest
â password can be updated 0.08s
â correct password must be provided to update password 0.08s
PASS Tests\Feature\Auth\RegistrationTest
â registration screen can be rendered 0.07s
â new users can register 0.07s
PASS Tests\Feature\ProfileTest
â profile page is displayed 0.19s
â profile information can be updated 0.07s
â email verification status is unchanged when the email address is unchanged 0.08s
â user can delete their account 0.08s
â correct password must be provided to delete account 0.10s
Tests: 26 passed (64 assertions)
Duration: 8.40s
3. Les factories Eloquent đâïž
đ§© Quâest-ce quâune Factory Laravel ?
Une factory est un outil fourni par Laravel pour générer automatiquement des données de test réalistes.
Elle permet de créer facilement :
- des objets Eloquent cohérents (User, Todo, Liste, etc.),
- avec des valeurs alĂ©atoires mais crĂ©dibles (texte, dates, boolĂ©ensâŠ),
- et surtout sans écrire manuellement chaque champ.
Les factories sont essentielles pour les tests, car elles permettent :
- de simplifier la crĂ©ation dâentrĂ©es en base,
- dâĂ©viter de dupliquer du code,
- dâisoler les tests (chaque test crĂ©e ses propres donnĂ©es),
et dâobtenir des tests prĂ©cis, reproductibles et rapides.
Les fichiers de factories se trouvent dans le dossier database/factories/
note : Laravel fournit déjà une factory pour User : UserFactory.php.
3.1. VĂ©rifier la factory User đ§âđ»âïž
Ouvre le fichier suivant : database/factories/UserFactory.php
Tu dois y trouver une méthode definition() qui ressemble à ceci :
<?php
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$'.strtr('password-hash', ['.' => '/']), // ou Hash::make(...)
'remember_token' => Str::random(10),
];
}
Lâimportant pour nous est :
đ User::factory()->create() permet de crĂ©er facilement un utilisateur de test valide.
3.2. CrĂ©er une factory pour Listes đâïž
On veut pouvoir gĂ©nĂ©rer des listes de Todos pour les tests (ex. âMaisonâ, âTravailâ, etc.).
Crée la factory : php artisan make:factory ListesFactory --model=Listes
Puis complĂšte database/factories/ListesFactory.php :
<?php
use App\Models\Listes;
use Illuminate\Database\Eloquent\Factories\Factory;
class ListesFactory extends Factory
{
protected $model = Listes::class;
public function definition(): array
{
return [
'titre' => fake()->words(2, true), // par ex. "Maison", "Bureau perso"
];
}
}
đĄ Explication ListeFactory
Ici, on utilise fake()->words(2, true) pour générer un nom de liste avec 2 mots.
à partir de là , un simple Listes::factory()->create() dans un test insérera une ligne dans la table listes avec un champ titre cohérent.
A faire
â CrĂ©er une factory pour Todos (sans relations)
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Todos;
use App\Models\Listes;
use App\Models\User;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Todos>
*/
class TodosFactory extends Factory
{
protected $model = Todos::class;
public function definition(): array
{
return [
'texte' => fake()->sentence(3),
'termine' => false,
'important' => false,
'date_fin' => null,
'listes_id' => Listes::factory(), // crée une Liste associée
'user_id' => User::factory(), // crée un User associé
];
}
}
Avec cette factory, on peut déjà écrire :
<?php
$todos = Todos::factory()->create();
todos avec :
- un
texteréaliste, termine = false,important = false,- les FK
listes_idetuser_idĂnull(non associĂ©es pour lâinstant).
Câest suffisant pour des premiers tests sur les attributs du modĂšle Todo.
3.3. VĂ©rifier le bon fonctionnement des factories đąâïž
Tinker est une console interactive fournie par Laravel, basĂ©e sur PsySH, qui permet dâexĂ©cuter du code PHP en direct au sein de ton application.
Câest un outil extrĂȘmement pratique pour :
- tester rapidement des modĂšles Eloquent,
- manipuler la base de données depuis le shell,
- vĂ©rifier le fonctionnement dâune factory,
- expérimenter un morceau de logique métier,
- déboguer un comportement sans écrire de route ni de test.
â¶ïž Ouvrir Tinker
Dans ton terminal (Ă la racine du projet) : php artisan tinker
Tu obtiens alors une console interactive :
Psy Shell v0.11.8 (PHP 8.2 âŠ)
>>>
Fix problĂšme đȘČ
- penser Ă ajouter
use HasFactory;dans le model de Todos - Vider le cache Laravel
php artisan optimize:clear
composer dump-autoload
3.4. Todo liĂ© Ă une Liste et Ă un User đâïž
Pour des tests plus complets (relations Eloquent), on peut demander à la factory Todo de créer automatiquement une Liste et un User associés.
code TodoFactory
<?php
use App\Models\Todos;
use App\Models\Listes;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class TodosFactory extends Factory
{
protected $model = Todos::class;
public function definition(): array
{
return [
'texte' => fake()->sentence(3),
'termine' => false,
'important' => false,
'date_fin' => null,
'listes_id' => Listes::factory(), // crée une Liste associée
'user_id' => User::factory(), // crée un User associé
];
}
}
En configurant listes_id et user_id avec Liste::factory() et User::factory(), on obtient un comportement trĂšs puissant :
<?php
$todo = Todos::factory()->create();
réalise en réalité :
- crĂ©ation dâun
Userde test, - crĂ©ation dâune
Listesde test, - création du
Todoslié à ces deux enregistrements.
Cela simplifie énormément les tests qui portent à la fois sur Todos et sur ses relations (ex. todos->listes, todos->user).
âïž Tester une factory
> App\Models\Listes::factory()->create();
= App\Models\Listes {#6211
titre: "eos ut",
updated_at: "2025-12-06 13:09:32",
created_at: "2025-12-06 13:09:32",
id: 4,
}
Résultat : un nouvel enregistrement todos est inséré dans la base de développement.
âïž CrĂ©er un utilisateur
> App\Models\User::factory()->create();
= App\Models\User {#6632
name: "Diane Lambert",
email: "pauline27@example.net",
email_verified_at: "2025-12-06 13:14:50",
#password: "$2y$12$mynJ8kscphRfl1KCdRRVR.XS8hKU0dxzQvaBkTWWc8P9TkgonEgEq",
#remember_token: "nNiqZwe2AN",
updated_at: "2025-12-06 13:14:51",
created_at: "2025-12-06 13:14:51",
id: 3,
}
âïž Tester la factory Todos
> App\Models\Todos::factory()->create();
= App\Models\Todos {#5520
texte: "Ut rerum praesentium fugit.",
termine: false,
important: false,
date_fin: null,
listes_id: 5,
user_id: 4,
updated_at: "2025-12-06 13:22:15",
created_at: "2025-12-06 13:22:15",
id: 9,
}
âïž Lister les enregistrements existants : App\Models\Todos::all();
4. Tests Unitaires : modĂšle Eloquent đ§±âïž
Dans cette Ă©tape, nous allons vĂ©rifier le comportement du modĂšle Todos Ă lâaide de tests unitaires :
- relations
Todos â ListesetTodos â User, - valeurs par dĂ©faut de certains attributs (
termine,important, etc.).
Lâobjectif est de valider le modĂšle sans passer par les routes ni les vues.
4.1 CrĂ©ation du test de modĂšle đ§Șâïž
GénÚre un test unitaire dédié au modÚle Todos :
php artisan make:test TodosModelTest --unit
tests/Unit/TodosModelTest.php
Modifier lâen-tĂȘte du fichier pour quâil Ă©tende bien la classe de test Laravel (et pas le TestCase brut de PHPUnit), afin de pouvoir utiliser les factories et la base de donnĂ©es de test.
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Models\Todos;
use App\Models\Listes;
use App\Models\User;
class TodosModelTest extends TestCase
{
use RefreshDatabase;
// Les tests viendront ici
}
đĄ Pourquoi utiliser Tests\TestCase et RefreshDatabase ?
Tests\TestCasecharge le contexte Laravel complet (config, Eloquent, etc.) dans les tests, mĂȘme dans tests/Unit.RefreshDatabaserelance les migrations pour chaque test afin de garantir une base de test propre (pas de pollution entre tests).
4.2 Tester la relation Todos â Listes đâïž
Ton modÚle Todos déclare une relation :
<?php
public function listes(): BelongsTo
{
return $this->belongsTo(Listes::class)->withDefault();
}
Dans TodosModelTest :
<?php
public function test_un_todos_appartient_a_une_liste()
{
// Arrange : création d'une liste
$liste = Listes::factory()->create();
// Act : création d'un Todos lié à cette liste
$todo = Todos::factory()->for($liste, 'listes')->create();
// Assert : la relation renvoie bien la bonne liste
$this->assertTrue($todo->listes->is($liste));
}
đĄ DĂ©tail sur for($liste, 'listes')
Listes::factory()->create()crĂ©e une ligne dans la table listes.Todos::factory()->for($liste, 'listes')->create()demande Ă Laravel de remplir la clĂ© Ă©trangĂšre correspondant Ă la relation listes dans le modĂšle Todos.- Lâassertion
is()vĂ©rifie que$todo->listeset$listereprĂ©sentent le mĂȘme enregistrement.
đ Relancer les tests : php artisan test
A faire
Tester la relation Todos â User đ€
<?php
public function test_un_todos_appartient_a_un_utilisateur()
{
// Arrange : création d'un utilisateur
$user = User::factory()->create();
// Act : création d'un Todos lié à cet utilisateur
$todo = Todos::factory()->for($user, 'user')->create();
// Assert : la relation renvoie bien le bon utilisateur
$this->assertTrue($todo->user->is($user));
}
đĄ Pourquoi tester les relations ?
Ces tests garantissent que :
- les clés étrangÚres (
listes_id, user_id)sont correctement utilisées, - les méthodes
listes()etuser()renvoient bien les modĂšles attendus.
En cas de renommage de colonne, de modĂšle ou de relation, ces tests serviront de garde-fous.
A faire
Tester les valeurs par dĂ©faut (termine, important) â
<?php
public function test_un_todos_est_non_termine_et_non_important_par_defaut()
{
// Act : création d'un Todos sans préciser termine/important
$todo = Todos::factory()->create();
// Assert : les valeurs par défaut sont respectées
$this->assertFalse($todo->termine);
$this->assertFalse($todo->important);
}
5.Tests de validation đ§źâïž
Nous allons maintenant Ă©crire des tests de validation pour le formulaire dâajout dâun Todo.
đŻ Objectifs"
- Vérifier que certains champs sont obligatoires (
textenotamment). - VĂ©rifier que certains champs respectent des contraintes (longueur minimale, format de dateâŠ).
- VĂ©rifier quâun Todo valide est bien créé en base.
5.1 PrĂ©parer un test dĂ©diĂ© đâïž
Crée un test de type Feature php artisan make:test TodosValidationTest
Cela créé un fichier dans tests/Feature/TodosValidationTest.php, modifier le code ainsi :
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Models\Listes;
use App\Models\Todos;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class TodosValidationTest extends TestCase
{
use RefreshDatabase;
/**
* Méthode utilitaire pour poster un Todo avec des données par défaut
*/
private function postTodo(array $overrides = [])
{
$user = User::factory()->create();
$this->actingAs($user);
$liste = Listes::factory()->create();
$data = array_merge([
'texte' => 'Acheter du café',
'date_fin' => now()->addDay()->format('Y-m-d\TH:i'),
'priority' => 0, // bouton radio importance
'categories' => [], // tableau de catégories (checkbox)
'liste' => $liste->id, // correspond Ă $request->input('liste')
], $overrides);
return $this->post('/action/add', $data);
}
đĄ Pourquoi une mĂ©thode postTodo() ?
Cette méthode permet de :
- centralise la construction dâun jeu de donnĂ©es valide,
- permet dâĂ©crire des tests plus courts en ne modifiant que les champs Ă tester,
- garantit que tous les autres champs restent cohérents (liste existante, user connecté, etc.).
5.2 texte est obligatoire âïžâïž
Premier cas : le champ texte doit ĂȘtre obligatoire.
<?php
public function test_texte_est_obligatoire()
{
$response = $this->postTodo(['texte' => '']);
$response->assertSessionHasErrors('texte');
$this->assertDatabaseCount('todos', 0);
}
question "đĄ Comportement attendu cĂŽtĂ© contrĂŽleur ?"
Dans ton contrĂŽleur qui traite /action/add, tu dois avoir quelque chose comme :
<?php
$validated = $request->validate([
'texte' => ['required', 'string'],
// autres rĂšglesâŠ
]);
- si
texteest vide, Laravel renvoie une erreur de validation sur ce champ, - aucun
Todosnâest créé en base.
mais
FAIL Tests\Feature\TodosValidationTest
⚯ texte est obligatoire 0.11s
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
FAILED Tests\Feature\TodosValidationTest > texte est obligatoire
Session is missing expected key [errors].
Failed asserting that false is true.
at tests\Feature\TodosValidationTest.php:40
36â public function test_texte_est_obligatoire()
37â {
38â $response = $this->postTodo(['texte' => '']);
39â
â 40â $response->assertSessionHasErrors('texte');
41â $this->assertDatabaseCount('todos', 0);
42â }
43â }
44â
Il faut adapter le test au contrĂŽleur actuel ! Le contrĂŽleur, en cas de texte vide, ne renvoie pas dâerrors bag, mais :
- déclenche une ValidationException,
- la catch renvoie un
redirect()->route('todo.liste')->with('message', "...").
Donc le test doit vérifier :
- la redirection vers la route,
- la présence du message en session,
- lâabsence de nouvelle ligne dans todos.
<?php
public function test_texte_est_obligatoire()
{
$response = $this->postTodo(['texte' => '']);
$response->assertRedirect(route('todo.liste'));
$response->assertSessionHas('message', "Veuillez saisir un ToDo d'une longueur max de 255 caractĂšres");
$this->assertDatabaseCount('todos', 0);
}
PASS Tests\Feature\TodosValidationTest
â texte est obligatoire 0.11s
Tests: 28 passed (69 assertions)
Duration: 6.48s
đ© Mais quelle est la bonne pratique ?
A faire : longueur minimale
Actuellement, la rĂšgle est 'texte' => 'required|string|max:255',
â¶ïž La rĂšgle doit Ă prĂ©sent ĂȘtre d'avoir une contrainte supplĂ©mentaire, une longueur minimale de 3 caractĂšres
- Implémenter cette rÚgle
- Faites en sorte qu'elle soit bien prise en compte dans votre interface
- Tester cette rĂšgle dans les features de tests.
dans le controleur :
<?php
$request->validate([
'texte' => 'required|string|min:3|max:255',
]);
<?php
public function test_texte_doit_avoir_une_longueur_minimale()
{
$response = $this->postTodo(['texte' => 'ab']); // 2 caractĂšres
$response->assertSessionHasErrors('texte');
$this->assertDatabaseCount('todos', 0);
}
ExĂ©cution ciblĂ©e des tests de validation â¶ïž
Pour exécuter uniquement cette classe de tests :
php artisan test --filter=TodosValidationTest
5.3 Cas nominal ââïžâïž
Il est important de tester aussi le scĂ©nario heureux đ :
quand toutes les donnĂ©es sont valides, le Todo doit ĂȘtre créé.
<?php
public function test_un_todos_valide_est_cree()
{
$response = $this->postTodo(); // toutes les valeurs par défaut sont valides
$response->assertSessionDoesntHaveErrors();
$response->assertRedirect(); // ou ->assertRedirect('/'); selon ton contrĂŽleur
$this->assertDatabaseCount('todos', 1);
$this->assertDatabaseHas('todos', [
'texte' => 'Acheter du café',
'termine' => 0,
'important' => 0,
]);
}
đĄ Pourquoi ce test est essentiel ?
- Il vérifie que la création fonctionne en cas de données valides.
- Il sert de rĂ©fĂ©rence pour les autres tests de validation : ils ne doivent empĂȘcher que les donnĂ©es invalides.
- En cas de modification ultérieure du contrÎleur, ce test permet de détecter une régression sur le CAS NOMINAL.
Available assertions đ
Il existe de nombreuses assertions différentes. Elles sont disponible dans la documentation de Laravel.
6. Gestion de la base de donnĂ©es pendant les tests đ§°âïž
Jusquâici, nous avons Ă©crit des tests qui crĂ©ent des utilisateurs, des listes et des todos Ă lâaide des factories.
Il est maintenant important de bien comprendre comment Laravel gÚre la base de données pendant les tests.
đŻ Objectifs
- Comprendre comment isoler chaque test (pas de pollution entre tests).
- Savoir sur quelle base sâexĂ©cutent les tests (
.env.testing). - Utiliser les assertions
assertDatabaseHas,assertDatabaseMissing,assertDatabaseCount.
6.1 Le trait RefreshDatabase đâïž
documentation Laravel sur database-testing
Laravel fournit le trait use Illuminate\Foundation\Testing\RefreshDatabase;
Ce trait, utilisé dans une classe de test, garantit que :
- les migrations sont exécutées pour la base de test,
- la base est remise à zéro entre les tests (soit par migrate:fresh, soit par transactions selon le driver).
Exemple (déjà utilisé dans tes tests) :
<?php
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class TodosValidationTest extends TestCase
{
use RefreshDatabase;
// ...
}
đĄ Que fait RefreshDatabase exactement ?
- Avant le premier test, Laravel exécute
php artisan migratesur la connexion de test. - Entre les tests, il remet la base dans un état propre (
rollbackoumigrate:freshselon le driver). - Cela permet de sâassurer que chaque test est indĂ©pendant des autres : aucun enregistrement laissĂ© par un test ne doit influencer un autre test.
6.2 Quelle base est utilisĂ©e pour les tests ? đïžâïž
Laravel choisit la base de données de test via Le fichier .env.testing ou éventuellement des variables dans phpunit.xml
Dans ton cas, tu as configuré une base MySQL dédiée, par exemple :
dans .env.testing
APP_ENV=testing
APP_DEBUG=true
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todo_test
DB_USERNAME=laravel_test
DB_PASSWORD=secret
Pendant les tests, on ne touche jamais à la base de développement (todo2025) :
tout se passe dans la base todo_test.
đĄ Comment vĂ©rifier que Laravel utilise bien la bonne base ?
- Tu peux temporairement ajouter un test âde debugâ :
<?php
public function test_voir_la_connexion_de_test() {
$this->assertSame('mysql', config('database.default'));
$this->assertSame('todo_test', config('database.connections.mysql.database'));
}
6.3 ExĂ©cuter les tests â¶ïžâïž
En gĂ©nĂ©ral, tu nâas pas besoin de te soucier manuellement des migrations : RefreshDatabase sâen charge.
Mais si tu modifies les migrations ou la structure de la base, tu peux forcer un reset complet :
php artisan migrate:fresh --env=testing
php artisan test
đĄ Quand utiliser migrate:fresh --env=testing ?
- Quand tu as modifié une migration existante (ajout/suppression de colonnes).
- Quand tu veux repartir dâune base de test complĂštement propre.
- à éviter en production, bien sûr : cela supprime toutes les tables avant de les recréer.
7. Tests dâauthentification đâïž
Laravel gĂ©nĂšre automatiquement une sĂ©rie complĂšte de tests dâauthentification et de sĂ©curitĂ©, via Breeze ou Jetstream.
Ces tests couvrent déjà toutes les fonctionnalités essentielles :
- affichage des formulaires de connexion / inscription,
- validation des identifiants,
- impossibilité de se connecter avec un mot de passe incorrect,
- confirmation de mot de passe,
- mise Ă jour du mot de passe,
- réinitialisation de mot de passe,
- vĂ©rification dâe-mail,
- dĂ©connexion de lâutilisateur.
Ces tests se trouvent dans tests/Feature/Auth/
Pourquoi conserver ces tests ? đĄïž
Ces tests assurent automatiquement :
- que lâauthentification reste fonctionnelle aprĂšs une mise Ă jour,
- que les étudiants ne cassent pas la sécurité en modifiant une vue ou une route,
- que chaque changement sur les routes ou les middlewares continue de respecter les rĂšgles Laravel (auth, verified, etc.).
- Ils constituent une base solide pour éviter les régressions pendant le développement.
7.2 Tests dâaccĂšs aux routes protĂ©gĂ©es (middleware auth) đâïž
Il peut ĂȘtre utile dâajouter un seul test d'exemple dans ton TP pour illustrer comment vĂ©rifier quâune route est bien protĂ©gĂ©e par auth.
<?php
public function test_invite_ne_peut_pas_acceder_aux_todos()
{
$response = $this->get('/todos');
$response->assertRedirect(route('login'));
}
7.3 Tests liĂ©s Ă l'autorisation (Policies) đ§âïž
Lorsque tu ajoutes une policy pour restreindre lâaccĂšs aux Todos :
- un utilisateur ne peut modifier que ses propres Todos,
- un utilisateur ne peut supprimer que ses Todos, etc.,
tu peux tester ces rĂšgles simplement avec :
<?php
public function test_un_utilisateur_ne_peut_pas_modifier_le_todo_d_un_autre()
{
$a = User::factory()->create();
$b = User::factory()->create();
$todo = Todos::factory()->for($a, 'user')->create();
$response = $this->actingAs($b)->post("/todos/{$todo->id}/edit", [
'texte' => 'H4ck',
]);
$response->assertForbidden();
}
Laravel renverra automatiquement 403 Forbidden si la policy refuse lâaccĂšs.
8. IntĂ©gration dans GitHub Actions âïžâïž
đŻ Objectif : exĂ©cuter automatiquement les tests Laravel Ă chaque push ou pull request sur GitHub, avec un seuil de couverture minimal.
đ IdĂ©e clĂ© :
- En local, tu peux utiliser MySQL (
todo_test). - En CI GitHub Actions, on va utiliser SQLite en mémoire (plus simple, plus rapide), en écrivant un
.env.testingspécifique dans le workflow. - On active la couverture de tests pour mesurer la part du code réellement exécutée par les tests, et on impose un seuil minimal (80 %).
8.1. CrĂ©er le workflow tests.yml đ§Ÿâïž
Dans ton projet, crée un fichier :
.github/workflows/tests.yml
Avec le contenu suivant :
name: tests
on:
push:
pull_request:
jobs:
laravel-tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: todo_test
MYSQL_USER: laravel_test
MYSQL_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -proot"
--health-interval=10s
--health-timeout=5s
--health-retries=10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, pdo_mysql
coverage: xdebug
- name: Install PHP dependencies
run: composer install --no-interaction --prefer-dist
# âŹïž Partie frontend / Vite : crĂ©ation du manifest.json
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install frontend dependencies
run: npm ci
- name: Build assets
run: npm run build
# âŹïž On aligne l'environnement de la CI sur ton env de test local
- name: Prepare environment file
run: cp .env.testing .env
- name: Run migrations
run: php artisan migrate --force
- name: Run tests with coverage
env:
XDEBUG_MODE: coverage
run: php artisan test --coverage --min=80
8.2. Mesurer la couverture en local đâïž
DĂ©finition đĄ
La couverture de code est une métrique qui peut vous permettre de comprendre la part testée de votre source. Cette métrique est trÚs utile, car elle peut vous aider à évaluer la qualité de votre suite de tests.
phpunit regarde quelles lignes ont été "utilisées" dans le code quand on a lancé les tests unitaires. Ensuite en fonction du nombre de lignes utilisées par rapport au nombre de lignes total du fichier, phpunit calcule un taux de couverture pour le fichier.
Dans notre CI :
- le job GitHub Actions réussit si la couverture est ℠80 %
- il échoue si la couverture descend sous 80 %.
En local, tu peux également mesurer la couverture php artisan test --coverage --min=80 --coverage-html ./report
L'option --coverage-html ./report permet de générer un rapport, mesurant la couverture de notre application.

đ„ Ici le taux est de \(62.45%\) donc trĂšs largement en dessous du seuil de --coverage --min=80. Donc si on laisse ce taux dans la CI, l'Ă©chec est assurĂ© !
Taux de couverture
â¶ïž Modifier le fichier tests.yml pour vous assurer que le taux de couverture de 80% ne soit pas bloquant.
run: php artisan test --coverage --min=80 || true
Fix problem Xdebug's coverage mode
symptĂŽmes :
(base) PS C:\wamp64\www\todo2026> php artisan test --coverage --min=80
ERROR Code coverage driver not available. Did you set Xdebug's coverage mode?
Dans le "bon" php.ini, vérifier
xdebug.mode=develop,coverage
xdebug.start_with_request=no
Cela transforme la couverture en garde-fou qualité :
si un développeur commente des tests ou ajoute beaucoup de code non testé, la CI refusera la Pull Request ou signalera le problÚme sur le push.
8.3. Lancer la CI aprĂšs les modifications â âïž
Une fois le workflow en place, tu peux tester le pipeline complet :
vendor/bin/pint
php artisan test
git add .
git commit -m "Intégration de l'environnement de tests et de la couverture"
git push -u origin main
Sur GitHub, onglet Actions, tu dois voir le workflow tests sâexĂ©cuter automatiquement Ă chaque push / pull request.

Fix probleme Vite
Verifier dans vos *.blade.php pour que le SASS soient utiliser (app.blade.php, guest.blade.php)
<?php
<!-- Styles et Scripts : Utilisation SASS -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
vite.config.php
<?php
laravel({
input: [
'resources/sass/app.scss',
'resources/js/app.js',
],
refresh: true,
}),
Conclusion â
- Un environnement de test Laravel fonctionnel.
- Des tests unitaires, fonctionnels et API.
- Une mesure automatique de couverture.
- Une exécution automatisée en CI GitHub Actions.