Retour aux articles
Laravel Pest

Tester les API sur Laravel avec PestPHP

Quand on met en place une API sur Laravel, la question que nous avons tendance à nous poser est : comment tester cette API ? Aujourd'hui, nous allons voir comment tester une API sur Laravel avec PestPHP.

Introduction

Dans cet article, je ne vais pas vous présenter PestPHP, et donc je vous invite à regarder cette vidéo de Ludovic pour en savoir plus sur PestPHP.

Nous allons parti d'un article de Steve McDougall qui explique comment tester les réponses d'API avec PestPHP.

Contexte

Pour illustrer notre exemple, nous avons une API qui retourne une liste de livres. Dans l'article de Steve, il a mis en place des Fixtures pour simuler un retour de réponse json de notre end-point. Je vais vous coller le code pour vous éviter de faire les aller-retour entre les deux articles.

function fixture(string $name): array
{
$file = file_get_contents(
filename: base_path("tests/Fixtures/$name.json"),
);
 
if(! $file) {
throw new InvalidArgumentException(
message: "Cannot find fixture: [$name] at tests/Fixtures/$name.json",
);
}
 
return json_decode(
json: $file,
associative: true,
);
}

Avec ceci, vous pouvez créer des Fixtures pour simuler des réponses de votre API. Avec un exemple donné par Steve dans son article, nous avons ceci :

it('can get a list of books from the API', function () {
$responseData = fixture('BooksApi/book-list');
 
Http::fake([
'*' => Http::response(
body: $responseData,
status: 200,
),
]);
 
$response = Http::get('https://books-api.com/books');
 
expect($response->json())->toEqual($responseData);
});

Il est important de noter que la création de fixtures permet de donner un modèle de retour de notre API aux développeurs front-end pour qu'ils puissent travailler en parallèle avec nous.

Dans ce code, on crée une fausse réponse de notre API avec la méthode fake de Http dans laquelle on lui donne le retour json souhaité. Ensuite, on fait une requête sur notre API avec la méthode get de Http. Et pour finir, on compare la réponse de notre API avec la réponse de notre Fixture.

La problématique

Si vous exécutez ce test, il va toujours passer ✅, en sachant que vous avez fait une fake request Http en lui donnant déjà le body de la response. Et donc, vous n'avez pas de test complet de votre API. Parce que dans tous les cas, vous n'aurez qu'à modifier les données de votre Fixture pour vous assurer que votre retour est toujours le même.

La solution

Couplé à la création de Fixture, pour se rassurer que si notre Resource API change de structure, on aura un test qui va échouer, on va utiliser la méthode assertJsonStructure de PHPUnit.

describe('get books', function (): void {
beforeEach(function (): void {
$this->headers = [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
];
 
getJson(
uri: '/v1/books',
headers: $this->headers,
)
->assertStatus(200)
->assertJsonStructure([
'data' => [
[
'id',
'title',
'author',
],
],
]);
});
 
it('can get a list of books from the API', function () {
$responseData = fixture('BooksApi/book-list');
 
Http::fake([
'*' => Http::response(
body: $responseData,
status: 200,
),
]);
 
$response = Http::get('https://books-api.com/books');
 
expect($response->json())->toEqual($responseData);
});
})

Alors que fait ce test ? avant chaque instruction qui peuvent être définies le code dans notre fonction beforeEach va s'exécuter. Pour l'exemple, nous avons mis notre requête Http dans cette fonction, mais vous pouvez mettre le getJson dans le it() directement.

  • Premièrement, on crée un tableau $headers qui contient les headers de notre requête.
  • Ensuite, on fait une requête sur notre vrai end-point qui se trouve dans notre fichier de routing routes/api.php (/v1/books) avec la méthode getJson de Laravel et on s'assure que le body de notre réponse est exactement ce que nous avons écrit.
  • Enfin, on fait une fake request Http en lui donnant le body de notre Fixture et on s'assure que la réponse de notre API est exactement ce que nous avons écrit.

Les deux tests vont passer ✅, mais si vous modifiez la structure de votre Resource API, le premier test va échouer ❌ et vous allez pouvoir corriger votre code. Ainsi, vous allez garder votre retour Resource API défini dans votre classe BookResource en accord avec votre fixture.

Tester ses API est très important et permet de vous assurer que votre API fonctionne correctement et que vous n'avez pas de régression.