Chargement...

Écriture de tests unitaires en C# (xUnit, NUnit, MSTest)

Apprenez à écrire des tests unitaires en C# avec xUnit, NUnit et MSTest pour améliorer la qualité du code.

En développement logiciel, les tests unitaires (unit tests) permettent de vérifier que les plus petites parties d’une application (méthodes, classes ou fonctions) fonctionnent correctement de manière isolée. En C#, les frameworks de test les plus utilisés sont xUnit, NUnit et MSTest. Les tests unitaires aident à détecter les erreurs à un stade précoce, améliorent la qualité du code et permettent un refactoring en toute sécurité.


Qu’est-ce qu’un test unitaire ?

Les tests unitaires vérifient si une méthode produit le résultat attendu pour des entrées données. Les tests sont généralement isolés pour chaque scénario et indépendants des dépendances externes (base de données, système de fichiers, accès réseau).


// Exemple : méthode à tester
public class Calculatrice
{
    public int Additionner(int a, int b) => a + b;
}

Dans l’exemple ci-dessus, la méthode Additionner représente l’unité à tester.


Créer un projet de test

Vous pouvez facilement créer un projet de test avec Visual Studio ou la CLI .NET :


// Créer un projet de test avec xUnit
dotnet new xunit -n Calculatrice.Tests
cd Calculatrice.Tests

// Ajouter une référence au projet principal
dotnet add reference ../Calculatrice/Calculatrice.csproj

Vous pouvez également utiliser les modèles nunit ou mstest :


dotnet new nunit -n NomDuProjet.Tests
dotnet new mstest -n NomDuProjet.Tests

Écriture de tests avec xUnit

xUnit est un framework moderne et flexible, largement adopté dans l’écosystème C#. L’attribut [Fact] désigne des tests indépendants, tandis que [Theory] est utilisé pour les tests paramétrés.


using Xunit;

public class CalculatriceTests
{
    [Fact]
    public void Additionner_DoîtRetournerLeRésultatCorrect()
    {
        // Arrange
        var c = new Calculatrice();

        // Act
        int resultat = c.Additionner(2, 3);

        // Assert
        Assert.Equal(5, resultat);
    }

    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(-1, 5, 4)]
    [InlineData(10, -2, 8)]
    public void Additionner_AvecDifférentesValeurs_DoîtFonctionner(int a, int b, int attendu)
    {
        var c = new Calculatrice();
        Assert.Equal(attendu, c.Additionner(a, b));
    }
}

Fact : teste un seul scénario. Theory : teste la même méthode avec plusieurs jeux de données.


Écriture de tests avec NUnit

NUnit est un framework de test puissant et anciennement établi dans le monde C#. Il est reconnu pour sa simplicité et sa grande variété d’assertions.


using NUnit.Framework;

[TestFixture]
public class CalculatriceTests
{
    private Calculatrice calc;

    [SetUp]
    public void Setup()
    {
        calc = new Calculatrice();
    }

    [Test]
    public void Additionner_Test()
    {
        int resultat = calc.Additionner(4, 6);
        Assert.That(resultat, Is.EqualTo(10));
    }

    [TestCase(1, 2, 3)]
    [TestCase(5, 5, 10)]
    public void Additionner_AvecPlusieursValeurs_Test(int a, int b, int attendu)
    {
        Assert.That(calc.Additionner(a, b), Is.EqualTo(attendu));
    }
}

Dans NUnit, la méthode [SetUp] s’exécute avant chaque test, et [TestCase] est utilisée pour les tests paramétrés.


Écriture de tests avec MSTest

MSTest est le framework de test intégré à Visual Studio par Microsoft. Il est particulièrement populaire dans les projets d’entreprise.


using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class CalculatriceTests
{
    private Calculatrice calc;

    [TestInitialize]
    public void Init()
    {
        calc = new Calculatrice();
    }

    [TestMethod]
    public void Additionner_Test()
    {
        int resultat = calc.Additionner(2, 8);
        Assert.AreEqual(10, resultat);
    }

    [DataTestMethod]
    [DataRow(1, 1, 2)]
    [DataRow(-3, 5, 2)]
    public void Additionner_AvecDifférentesValeurs_Test(int a, int b, int attendu)
    {
        Assert.AreEqual(attendu, calc.Additionner(a, b));
    }
}

Dans MSTest, [TestInitialize] est utilisée pour les préparations avant chaque test, et [DataTestMethod] pour les tests basés sur des données.


Méthodes d’assertion (Assert)

Tous les frameworks de test incluent des structures d’assertion similaires :


// Exemple : Test d’exception
[Fact]
public void Division_DoitLeverDivideByZeroException()
{
    var calc = new Calculatrice();
    Assert.Throws<DivideByZeroException>(() => calc.Diviser(5, 0));
}

Exécution des tests

Les tests peuvent être exécutés via la CLI ou dans Visual Studio :


// Exécuter les tests avec .NET CLI
dotnet test

Dans Visual Studio, la fenêtre “Test Explorer” permet d’exécuter les tests et d’afficher les résultats réussis ou échoués dans une interface graphique.


Mocking et isolation des dépendances

Le mocking est utilisé pour isoler les dépendances réelles de l’environnement de test. Cela garantit que les tests ne valident que la méthode cible, sans être affectés par des facteurs externes (base de données, service, etc.).


using Moq;
using Xunit;

public interface IServiceEmail
{
    void Envoyer(string adresse, string message);
}

public class EnregistrementUtilisateur
{
    private readonly IServiceEmail _email;
    public EnregistrementUtilisateur(IServiceEmail email) => _email = email;

    public void Enregistrer(string nom)
    {
        _email.Envoyer("admin@site.com", $"{nom} a été enregistré.");
    }
}

public class EnregistrementUtilisateurTests
{
    [Fact]
    public void Enregistrer_DoitEnvoyerUnEmail()
    {
        var mock = new Mock<IServiceEmail>();
        var enregistrement = new EnregistrementUtilisateur(mock.Object);

        enregistrement.Enregistrer("Jean");

        mock.Verify(m => m.Envoyer("admin@site.com", "Jean a été enregistré."), Times.Once);
    }
}

La bibliothèque Moq permet de créer des objets simulés (mocks) afin d’isoler l’environnement de test.


Organisation et nommage des tests


Exemple réel : Test de calcul du total d’une commande

L’exemple suivant teste le calcul du total d’une commande.


// Code applicatif
public class Commande
{
    public List<decimal> PrixProduits { get; set; } = new();
    public decimal Total() => PrixProduits.Sum();
}

// Test
public class CommandeTests
{
    [Fact]
    public void Total_DoitRetournerLeBonResultat()
    {
        var c = new Commande();
        c.PrixProduits.AddRange(new[] { 10m, 20m, 30m });
        Assert.Equal(60m, c.Total());
    }
}

Cet exemple montre un test unitaire simple qui garantit le bon fonctionnement de la logique métier.


Performance et meilleures pratiques


TL;DR

  • Test unitaire : Teste des unités de code isolées et de petite taille.
  • xUnit : Framework moderne, minimaliste et largement utilisé dans l’écosystème .NET.
  • NUnit : Framework classique avec de puissantes assertions et une approche basée sur les attributs.
  • MSTest : Solution Microsoft intégrée, totalement compatible avec Visual Studio.
  • Mocking : Isole les dépendances externes grâce à des objets simulés.
  • Modèle AAA : Suivez le schéma Arrange–Act–Assert pour structurer vos tests.
  • La commande dotnet test exécute tous les tests via la CLI.

Articles connexes