Pourquoi Tester Laravel avec PHPUnit ?
L'importance de tester un code est inégalable dans tout développement logiciel, et ce n'est pas moins vrai pour les applications basées sur le framework Laravel. En effet, une application complexe comme celle-ci nécessite une couche de sécurité supplémentaire pour s'assurer qu'elle fonctionne correctement en toutes circonstances. PHPUnit, l'un des frameworks de tests les plus populaires et robustes disponibles pour PHP, offre une solution complète pour automatiser ce processus.
Un cas d'utilisation concret est la gestion d'une application e-commerce : si vous n'avez pas de tests automatisés, il sera difficile de s'assurer que chaque fonctionnalité (ajout au panier, paiement sécurisé, etc.) fonctionne comme prévu sans intervention manuelle. Les tests permettent de vérifier automatiquement chaque partie de l'application et d'identifier les bugs dès qu'ils apparaissent.
Prerequis
- Connaissance approfondie de Laravel
- Connaissances en PHP avancées
- Familiarité avec PHPUnit
- Un environnement de développement sur votre machine (XAMPP, MAMP, WAMP)
- Composer pour gérer les dépendances
- Node.js et npm pour les packages tiers (si nécessaire)
Concepts fondamentaux
1. Ce qu'est un test ?
Un test est une vérification systématique d'une fonctionnalité de votre application pour s'assurer qu'elle produit le résultat attendu.
// Un simple test PHPUnit
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
public function testBasicExample()
{
$this->assertEquals(2, 1 + 1);
}
}
2. Structure d'un test de Laravel
Un test de Laravel est organisé autour de classes et méthodes spécifiques. Chaque méthode de test doit commencer par le mot-clé test.
// Un test de controller
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleControllerTest extends TestCase
{
use RefreshDatabase;
public function test_example_function()
{
$response = $this->get('/example');
$response->assertStatus(200);
$response->assertSee('Example Content');
}
}
3. Assertions
Les assertions sont les méthodes qui permettent de vérifier des conditions spécifiques.
// Vérification d'une valeur égale
$this->assertEquals($expected, $actual);
// Vérification d'un statut HTTP
$response->assertStatus(200);
// Vérification d'un contenu dans la réponse
$response->assertSee('Example Content');
4. Mocking
Le mocking est une technique utilisée pour simuler des objets ou des méthodes.
// Mocking un service
use App\Services\SomeService;
use Illuminate\Support\Facades\App;
public function test_service_function()
{
$mock = \Mockery::mock(SomeService::class);
App::instance(SomeService::class, $mock);
$mock->shouldReceive('someMethod')->andReturn(true);
$result = app(SomeService::class)->someMethod();
$this->assertTrue($result);
}
Mise en pratique : Projet fil rouge
1. Création du projet
composer create-project --prefer-dist laravel/laravel task-manager "8.*"
cd task-manager
npm install
npm run dev
php artisan serve
2. Création d'un modèle et une migration
php artisan make:model Task -m
Edit database/migrations/xxxx_xx_xx_xxxxxx_create_tasks_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTasksTable extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tasks');
}
}
Run migrations:
php artisan migrate
3. Création d'un contrôleur
php artisan make:controller TaskController --resource
Edit app/Http/Controllers/TaskController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
public function index()
{
$tasks = Task::all();
return view('tasks.index', compact('tasks'));
}
public function store(Request $request)
{
$task = new Task($request->all());
$task->save();
return redirect()->route('tasks.index');
}
}
4. Création des vues
Créez les fichiers de vue dans resources/views/tasks/. Par exemple, index.blade.php:
@extends('layouts.app')
@section('content')
<h1>Tasks</h1>
<a href="route('tasks.create')" class="btn btn-primary">Create New Task</a>
<ul>
@foreach ($tasks as $task)
<li>$task->title</li>
@endforeach
</ul>
@endsection
5. Création des tests
Créez un test pour le contrôleur:
php artisan make:test TaskControllerTest --unit
Edit tests/Unit/TaskControllerTest.php:
<?php
namespace Tests\Unit;
use App\Models\Task;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class TaskControllerTest extends TestCase
{
use RefreshDatabase;
public function test_index()
{
$tasks = Task::factory()->create(['title' => 'Example Task']);
$response = $this->get('/tasks');
$response->assertStatus(200);
$response->assertSee('Example Task');
}
public function test_store()
{
$data = [
'title' => 'New Task',
'description' => 'This is a new task.'
];
$response = $this->post('/tasks', $data);
$response->assertRedirect('/tasks');
$this->assertDatabaseHas('tasks', [
'title' => 'New Task'
]);
}
}
Erreurs frequentes et debugging
1. Mauvaise assertion
// ❌ Mauvais
$response->assertSee('Incorrect Content');
// ✅ Correct
$response->assertSee('Example Content');
2. Mocking incorrect
// ❌ Mauvais
$mock = \Mockery::mock(SomeService::class);
app()->instance(SomeService::class, $mock);
// ✅ Correct
$mock = \Mockery::mock(SomeService::class);
app()->instance(SomeService::class, $mock);
$mock->shouldReceive('someMethod')->andReturn(true);
3. Validation de données incorrecte
// ❌ Mauvais
$response = $this->post('/tasks', []);
$response->assertStatus(200); // Devrait être 422
// ✅ Correct
$response = $this->post('/tasks', [
'title' => ''
]);
$response->assertStatus(422);
Pour aller plus loin
1. Tests de unité vs tests d'intégration
En savoir la différence entre les tests de unité et les tests d'intégration est crucial pour une bonne architecture de test.
2. Traitement des exceptions
Apprendre à tester le traitement des exceptions peut aider à identifier rapidement les problèmes.
3. Tests asynchrones avec Laravel
Apprendre à tester les requêtes asynchrones peut être utile si vous travaillez sur des applications front-end et back-end.
Défi pratique
Créez un test pour une fonctionnalité spécifique de votre application, par exemple, la création d'une tâche avec une description vide. Assurez-vous que le test échoue correctement lorsque les données sont incorrectes et passe lorsque les données sont valides.