Loupe

Mettre en place des tests d'intégrations (ASP.NET Core) - partie 1 - les bases

Mais c'est quoi ça, les tests d'intégrations ?

Les tests d'intégrations sont un des nombreux types de tests qu'il est possible de mettre en place sur vos projets pour chasser les bugs.

pyramide tests.png


Voici la pyramide des types de test. Plus un type de test est haut dans la pyramide plus il est :

  • coûteux à mettre en place
  • long à s'exécuter
  • instable et sensible aux changement
  • et moins il y en a de mis en place.

A contrario, plus un type de test est en bas dans la pyramide et :

  • moins il est coûteux à mettre en place
  • plus il est rapide à s'exécuter
  • plus il est stable et cloisonné (et donc plus facile à maintenir)
  • plus il y en a de mis en place.


Si les tests d'interface vous intéressent, je vous conseille de jeter un oeil à l'article de Vivien : BrowserStack + Selenium : Tests multi-navigateurs en 5 minutes

Dans cet article, concentrons nous sur les tests d'intégrations. Ils permettent de tester avec du code, un ensemble de composants, contrairement à un test unitaire, qui lui a pour but de tester uniquement un composant isolé. Leur but est de valider un comportement attendu.

Si un test d'intégration ne fonctionne plus, ce n'est pas forcément trivial à solutionner. Ces tests ne sont pas binaires, ils peuvent tomber en erreur dans de nombreux cas, en voici quelques exemples :

  • vous avez introduit une régression quelque part dans l'enchaînement de votre code, ou dans une brique de votre code,
  • un des composants, ou une dépendance utilisés a un bug,
  • le fonctionnement a changé et le test est obsolète,
  • ...

Il est important de garder à l'esprit qu'ils ne se suffisent pas à eux-mêmes. Des tests unitaires, d'interface, manuels peuvent également être pertinents à mettre en place, tout dépend de votre contexte.
Pour une librairie technique, les tests unitaires et d'intégrations sont recommandés, mais pour un produit, ou un projet qui s'inscrit sur la durée, des tests d'interface et même manuels peuvent également s'ajouter a cette liste.

Pourquoi mettre en place des tests d'intégrations sur mon API ?

Comme expliqué au-dessus, les tests d'intégration permettent de valider un comportement attendu. Une API étant en général au coeur d'une application, elle doit être fiable et stable. La mise en place de tests (tout type), permet d'accroître cette fiabilité et cette stabilité. Cela peut-être notamment nécessaire pour être plus serein sur des phases de refactorisation du code pour ainsi s'assurer que tout fonctionne comme avant et ainsi s'assurer de ne pas avoir introduit de régression. Les tests d'intégrations sont un moyen assez simple de tester une API de bout en bout sans trop d'effort. 

La mise en place de tests d'intégrations peut se faire aussi bien sur une nouvelle API, voir même sur une API déjà développée. Mais attention, pour ce dernier scénario, en fonction des tests voulus et de l'architecture de l'API, cela peut être plus ou moins facile (voir quasi impossible) et parfois le temps alloué n'en vaut pas forcément la chandelle.

Quels sont les outils disponibles ?

Il existe plusieurs frameworks de test, les plus connus étant VSTest, xUnit, NUnit.
Dans mon exemple, je vais utiliser xUnit car je suis plus a l'aise avec, de plus, ayant commencé a faire des tests d'intégration en sur mon API dès Core 1.0, xUnit était un des seuls qui était compatible.

A ce framework de test, j'ai l'habitude d'ajouter SpecFlow, qui permet de faire du BDD (Behaviour Driven Development), et ainsi d'écrire des tests en langage naturel avec une syntaxe Given, When, Then. 

Comment mettre en place tout cela ?

Nous allons partir du postulat que nous avons déjà créé une API en ASP.NET Core que nous souhaitons tester.
Il faut ensuite, créer le projet de tests (C# > .NET Core > xUnit Test Project):

creation projet test d'integration.PNG

Et ajouter en référence notre API, ainsi que le package Microsoft.AspNetCore.TestHost que nous allons utiliser par la suite, pour monter en mémoire l'API.

test host.PNG

Une fois ces deux étapes réalisées, nous pouvons commencer à tester notre API ! 
Dans mon premier exemple, je souhaite tester que le endpoint "Get" de mon API me renvoie bien un tableau avec 2 chaînes de caractères précises et ainsi valider le comportement souhaité.

Côté API : 

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

Côté Test :

Le découpage se fait en 3 parties (Arrange, Act, Assert).

[Fact(DisplayName = "J'appelle la route values sur l'API, elle me renvoit un tableau avec value1, et value2")]
public async Task GetValues_ShouldBeOk()
{
    // Arrange
    var builder = WebHost.CreateDefaultBuilder();
    var server = new TestServer(builder
        .UseStartup<Startup>());
    var client = server.CreateClient();

    // Act
    var httpResponseMessage = await client.GetAsync("api/values");

    // Assert
    Assert.True(httpResponseMessage.IsSuccessStatusCode);
    var values = JsonConvert.DeserializeObject<string[]>(await httpResponseMessage.Content.ReadAsStringAsync());
    Assert.NotEmpty(values);
    Assert.Equal(2, values.Length);
    Assert.Contains(values, v => v == "value1");
    Assert.Contains(values, v => v == "value1");
}

La partie "Arrange" permet de préparer l'environnement nécéssaire au test, ici nous créons un serveur de test en mémoire (en utilisant Microsoft.AspNetCore.TestHost) basé sur le Startup de note API (ainsi nous avons exactement le même comportement que si on appelait l'API à la main comme un client classique). Le serveur nous permet d'obtenir un HttpClient que nous allons utiliser pour toutes les appels que nous souhaitons faire à l'API.

La partie "Act" permet d'effectuer l'action de notre test, ici nous appelons l'API et nous stockons le résultat de l'appel.

La partie "Assert" permet de valider que l'action valide le cas de test, ici nous vérifions que les valeurs retournées par l'appel sont bien "value1" et "value2".

Il ne reste plus qu'à lancer l'exécution du test ! Pour cela, rien de plus simple, dans la fenêtre "Test Explorer" de "Visual Studio" (après avoir build mon projet de test), il suffit de lancer les tests. 

test explorer.PNG

Aller plus loin 

Tout ça c'est bien, mais comment je fais pour en faire plus ?
Et bien, je vous invite lire la partie 2 de cet article, nous parlerons notamment de changement de configuration (appsettings), remplacement de service (via l'injection de dépendance), d'utilisation de EF Core In Memory.

Merci à Vivien, et William pour leur aide.

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus