Efectuer des tests unitaires de C# dans .NET à l’aide de dotnet test et de xUnit

Ce didacticiel montre comment créer une solution contenant un projet de test unitaire et un projet de code source. Pour suivre le didacticiel à l’aide d’une solution prédéfinie, affichez ou téléchargez l’exemple de code. Pour obtenir des instructions de téléchargement, consultez Exemples et didacticiels.

Créez la solution

Dans cette section, une solution contenant les projets source et de test est créée. La solution terminée a la structure de répertoire suivante :

/unit-testing-using-dotnet-test
    unit-testing-using-dotnet-test.sln
    /PrimeService
        PrimeService.cs
        PrimeService.csproj
    /PrimeService.Tests
        PrimeService_IsPrimeShould.cs
        PrimeServiceTests.csproj

Les instructions suivantes présentent les étapes de création de la solution de test. Consultez Commandes pour créer une solution de test pour obtenir des instructions permettant de créer la solution de test en une seule étape.

  • Ouvrez une fenêtre d’interpréteur de commandes.

  • Exécutez la commande suivante :

    dotnet new sln -o unit-testing-using-dotnet-test
    

    La commande dotnet new sln crée une nouvelle solution dans le répertoire unit-testing-using-dotnet-test.

  • Mettez le répertoire dans le dossier unit-testing-using-dotnet-test.

  • Exécutez la commande suivante :

    dotnet new classlib -o PrimeService
    

    La commande dotnet new classlib crée un nouveau projet de bibliothèque de classes dans le dossier PrimeService. La nouvelle bibliothèque de classes contient le code à tester.

  • Renommez Class1.cs en PrimeService.cs.

  • Remplacez le code dans PrimeService.cs par le code suivant :

    using System;
    
    namespace Prime.Services
    {
        public class PrimeService
        {
            public bool IsPrime(int candidate)
            {
                throw new NotImplementedException("Not implemented.");
            }
        }
    }
    
  • Le code précédent :

    • Lève une NotImplementedException avec un message indiquant qu’il n’est pas implémenté.
    • Est mis à jour plus loin dans le didacticiel.
  • Dans le répertoire unit-testing-using-dotnet-test, exécutez la commande suivante pour ajouter le projet de bibliothèque de classes à la solution :

    dotnet sln add ./PrimeService/PrimeService.csproj
    
  • Créez le projet PrimeService.Tests en exécutant la commande suivante :

    dotnet new xunit -o PrimeService.Tests
    
  • La commande précédente :

    • Crée le projet PrimeService.Tests dans le répertoire PrimeService.Tests. Le projet de test utilise xUnit comme bibliothèque de test.
    • Configure l’exécuteur de tests en ajoutant les éléments suivants <PackageReference />au fichier projet :
      • Microsoft.NET.Test.Sdk
      • xunit
      • xunit.runner.visualstudio
      • coverlet.collector
  • Ajoutez le projet de test au fichier solution en exécutant la commande suivante :

    dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
    
  • Ajoutez la bibliothèque de classes PrimeService en tant que dépendance au projet PrimeService.Tests :

    dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj  
    

Commandes pour créer la solution

Cette section récapitule toutes les commandes de la section précédente. Ignorez cette section si vous avez effectué les étapes de la section précédente.

Les commandes suivantes créent la solution de test sur un ordinateur Windows. Pour macOS et Unix, mettez à jour la commande ren vers la version du système d’exploitation de ren pour renommer un fichier :

dotnet new sln -o unit-testing-using-dotnet-test
cd unit-testing-using-dotnet-test
dotnet new classlib -o PrimeService
ren .\PrimeService\Class1.cs PrimeService.cs
dotnet sln add ./PrimeService/PrimeService.csproj
dotnet new xunit -o PrimeService.Tests
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

Suivez les instructions pour « Remplacer le code dans PrimeService.cs par le code suivant » dans la section précédente.

Créer un test

Une approche populaire dans le développement piloté par les tests (TDD) consiste à écrire un test (défaillant) avant d’implémenter le code cible. Ce didacticiel utilise l’approche TDD. La méthode IsPrime peut être appelée, mais n’est pas implémentée. Un appel de test vers IsPrime échoue. Avec TDD, un test connu pour échouer est écrit. Le code cible est mis à jour pour que le test réussisse. Vous continuez à répéter cette approche, en écrivant un test défaillant, puis en mettant à jour le code cible afin qu’il réussisse.

Mettez à jour le projet PrimeService.Tests :

  • Supprimez PrimeService.Tests/UnitTest1.cs.
  • Créez un fichierPrimeService.Tests/PrimeService_IsPrimeShould.cs.
  • Remplacez le code dans PrimeService_IsPrimeShould.cs par le code suivant :
using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    public class PrimeService_IsPrimeShould
    {
        [Fact]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var primeService = new PrimeService();
            bool result = primeService.IsPrime(1);

            Assert.False(result, "1 should not be prime");
        }
    }
}

L’attribut [Fact] déclare une méthode de test qui est exécutée par l’exécuteur de tests. Dans le dossier PrimeService.Tests, exécutez dotnet test. La commande dotnet test génère les deux projets et exécute les tests. L’exécuteur de tests xUnit contient le point d’entrée de programme qui permet d’exécuter les tests. dotnet test démarre l’exécuteur de tests à l’aide du projet de test unitaire.

Le test échoue, car IsPrime n’a pas été implémenté. À l’aide de l’approche TDD, n’écrivez que suffisamment de code pour que ce test réussisse. Mettez à jour IsPrime à l’aide du code suivant :

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

Exécutez dotnet test. Le test réussit.

Ajouter des tests

Ajoutez des tests de nombre premier pour 0 et -1. Vous pouvez copier le test créé à l’étape précédente et effectuer des copies du code suivant pour tester 0 et -1. Mais ne le faites pas, car il existe une meilleure façon de procéder.

var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

Assert.False(result, "1 should not be prime");

La copie du code de test quand seul un paramètre change entraîne une duplication de code et une surabondance de tests. Les attributs xUnit suivants permettent d’écrire une suite de tests similaires :

  • [Theory] représente une suite de tests qui exécutent le même code, mais qui ont des arguments d’entrée différents.
  • L’attribut [InlineData] spécifie des valeurs pour ces entrées.

Au lieu de créer de nouveaux tests, appliquez les attributs xUnit précédents pour créer une seule théorie. Remplacez le code suivant :

[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
    var primeService = new PrimeService();
    bool result = primeService.IsPrime(1);

    Assert.False(result, "1 should not be prime");
}

par le code suivant :

[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);

    Assert.False(result, $"{value} should not be prime");
}

Dans le code précédent, [Theory] puis [InlineData] activent le test de plusieurs valeurs inférieures à deux. Deux est le plus petit nombre premier.

Ajoutez le code suivant après la déclaration de classe et avant l’attribut [Theory] :

private readonly PrimeService _primeService;

public PrimeService_IsPrimeShould()
{
    _primeService = new PrimeService();
}

Exécutez dotnet test, et deux des tests échouent. Pour que tous les tests réussissent, mettez à jour la méthode IsPrime avec le code suivant :

public bool IsPrime(int candidate)
{
    if (candidate < 2)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

En suivant l’approche TDD, ajoutez d’autres tests défaillants, puis mettez à jour le code cible. Vous disposez de la version finale des tests et de l’implémentation complète de la bibliothèque.

La méthode IsPrime terminée n’est pas un algorithme efficace pour tester la primalité.

Ressources supplémentaires