Partager via


Bases de test unitaire

Cette rubrique décrit les principes fondamentaux de l'écriture et de l'exécution de tests unitaires dans l'Explorateur de tests de Visual Studio.Elle contient les sections suivantes :

Vue d'ensemble des tests unitaires

  • Démarrages rapides

Exemple MyBank Solution

Création de projets de test unitaire

Écriture des tests

Exécution des tests dans l'Explorateur de tests

  • Exécution et affichage des tests à partir de la barre d'outils de l'Explorateur de tests

  • Exécution des tests après chaque build

  • Filtrage et regroupement de la liste de tests

Débogage des tests unitaires

Outils supplémentaires pour les tests unitaires

  • Génération du code d'application à partir des tests

  • Génération de plusieurs tests à l'aide de méthodes de test pilotées par les données

  • Analyse de la couverture du code de test unitaire

  • Isolation des méthodes de test unitaire avec Microsoft Fakes

Vue d'ensemble des tests unitaires

L'Explorateur de tests de Visual Studio est conçu pour aider les développeurs et les équipes qui intègrent les tests unitaires à leurs pratiques de développement logiciel.Les tests unitaires vous permettent de garantir l'exactitude de votre programme en vérifiant que le code d'application se comporte comme escompté.Dans les tests unitaires, vous analysez les fonctionnalités de votre programme pour découvrir les comportements testables distincts que vous pouvez tester en tant qu'unités individuelles.Vous utilisez une infrastructure de test unitaire pour créer des tests de ces comportements et pour rendre compte des résultats de ces tests.

Les tests unitaires sont les plus efficaces lorsqu'ils font partie intégrante du workflow de votre développement logiciel.Dès que vous écrivez une fonction ou autre bloc de code d'application, vous créez des tests unitaires pour vérifier le comportement du code en réponse aux cas standard, limite et incorrects des données d'entrée, ainsi que les hypothèses explicites ou implicites du code.Dans la pratique de développement de logiciel appelée développement piloté par les tests, comme vous créez les tests unitaires avant d'écrire le code, vous utilisez les tests unitaires comme documentation de conception et comme spécifications fonctionnelles de la fonctionnalité.

L'Explorateur de tests offre un moyen souple et efficace d'exécuter vos tests unitaires et d'afficher leurs résultats dans Visual Studio.Visual Studio installe les infrastructures de tests unitaires Microsoft pour le code managé et le code natif.L'Explorateur de tests peut également exécuter des infrastructures de tests unitaires tierces et open source ayant implémenté les interfaces des composants additionnels de l'Explorateur de tests.Vous pouvez ajouter la plupart de ces infrastructures via le gestionnaire d'extensions de Visual Studio et la galerie Visual Studio.Voir Comment : installer des infrastructures de tests unitaires tiers

L'Explorateur de tests peut afficher tous vos tests ou uniquement les tests qui ont réussi, échoué, n'ont pas encore été exécutés ou ont été ignorés.Vous pouvez filtrer les tests de n'importe quelle vue sur le texte de la zone de recherche au niveau global ou en sélectionnant l'un des filtres prédéfinis.Vous pouvez exécuter une sélection des tests à tout moment.Lorsque vous utilisez Visual Studio Ultimate, vous pouvez exécuter automatiquement les tests après chaque build.Les résultats d'une série de tests sont immédiatement visibles dans la barre réussite/échec en haut de la fenêtre de l'Explorateur.Les détails d'un résultat de méthode de test sont affichés lorsque vous sélectionnez le test.

Démarrages rapides

Pour une introduction aux tests unitaires qui vous conduisent directement dans le code, consultez l'une des rubriques suivantes :

Exemple MyBank Solution

Dans cette rubrique, nous utilisons comme exemple le développement d'une application fictive, appelée MyBank.Vous n'avez pas besoin du code réel pour suivre les explications fournies dans cette rubrique.Les méthodes de test sont écrites en C# et présentées à l'aide de l'infrastructure de test unitaire Microsoft pour le code managé. Cependant, les concepts peuvent être facilement transférés vers d'autres langages et infrastructures.

Solution MyBank

Notre première tentative de conception de l'application MyBank inclut un composant Accounts (Comptes) qui représente un compte individuel et ses transactions avec la banque et un composant Database (Base de données) qui correspond à la fonction d'agrégation et de gestion des comptes individuels.

Nous créons une solution MyBank qui contient deux projets :

  • Accounts

  • BankDb

Notre première tentative de conception du projet Accounts comporte une classe destinée à détenir les informations de base d'un compte, une interface qui spécifie les fonctionnalités courantes de n'importe quel type de compte, comme le dépôt ou le retrait, et une classe dérivée de l'interface qui représente un compte courant.Nous commençons les projets Accounts (Comptes) en créant les fichiers sources suivants :

  • AccountInfo.cs définit les informations de base d'un compte.

  • IAccount.cs définit une interface IAccount standard pour un compte, y compris les méthodes pour déposer de l'argent sur un compte ou en retirer, et pour récupérer le solde du compte.

  • CheckingAccount.cs contient la classe CheckingAccount qui implémente l'interface IAccounts d'un compte courant.

On sait par expérience qu'un retrait sur un compte courant doit s'assurer que le montant retiré est inférieur au solde du compte.Aussi, nous remplaçons la méthode IAccount.Withdaw de CheckingAccount par une méthode qui vérifie cette condition.La méthode peut ressembler à ceci :

public void Withdraw(double amount)
{
    if(m_balance >= amount)
    {
        m_balance -= amount;
    }
    else
    {
        throw new ArgumentException(amount, "Withdrawal exceeds balance!")
    }
}

Maintenant que nous avons le code, il est temps de le tester.

Création de projets de test unitaire

Un projet de test unitaire reflète généralement la structure d'un seul projet de code.Dans l'exemple MyBank, vous ajoutez deux projets de test unitaire nommés AccountsTests et BankDbTests à la solution MyBanks.Les noms des projets de test sont arbitraires, mais adopter une convention d'affectation de noms standard est une bonne idée.

Pour ajouter un projet de test unitaire à une solution :

  1. Dans le menu Fichier, choisissez Nouveau, puis Projet (Ctrl+Maj+N).

  2. Dans la boîte de dialogue Nouveau projet, développez le nœud Installé, choisissez le langage que vous voulez utiliser pour votre projet de test, puis sélectionnez Test.

  3. Pour utiliser l'une des infrastructures de tests unitaires Microsoft, choisissez Projet de test unitaire dans la liste des modèles de projet.Sinon, choisissez le modèle de projet de l'infrastructure de tests unitaires que vous souhaitez utiliser.Pour tester le projet Accounts de notre exemple, vous devez le nommer AccountsTests.

    Mise en gardeAttention

    Certaines infrastructures de tests unitaires tierces et open source ne fournissent pas de modèle de projet Visual Studio.Pour plus d'informations sur la création d'un projet, consultez la documentation relative à l'infrastructure.

  4. Dans votre projet de test unitaire, ajoutez une référence au projet de code testé : le projet Accounts (Comptes) dans notre exemple.

    Pour créer la référence au projet de code :

    1. Sélectionnez le projet dans l'Explorateur de solutions.

    2. Dans le menu Projet, choisissez Ajouter une référence.

    3. Dans la boîte de dialogue Gestionnaire de références, ouvrez le nœud Solution et choisissez Projets.Sélectionnez le nom du projet de code et fermez la boîte de dialogue.

Chaque projet de test unitaire contient les classes qui reflètent les noms des classes du projet de code.Dans notre exemple, le projet AccountsTests contient les classes suivantes :

  • la classe AccountInfoTests contient les méthodes de test unitaire pour la classe AccountInfo du projet BankAccount ;

  • la classe CheckingAccountTests contient les méthodes de test unitaire pour la classe CheckingAccount.

Écriture des tests

L'infrastructure de tests unitaires que vous utilisez et Visual Studio IntelliSense vous guident à travers la création de tests unitaires pour un projet de code.Pour s'exécuter dans l'Explorateur de tests, la plupart des infrastructures nécessitent que vous ajoutiez des attributs spécifiques pour identifier les méthodes de test unitaire.Les infrastructures fournissent également un moyen, généralement par le biais d'instructions assert ou d'attributs de méthode, pour indiquer si la méthode de test a réussi ou échoué.D'autres attributs identifient les méthodes facultatives d'installation lors de l'initialisation des classes et avant chaque méthode de test, ainsi que les méthodes de démontage qui sont exécutées après chaque méthode de test et avant la destruction de la classe.

Le modèle AAA (Arrange, Act, Assert) est un moyen couramment utilisé pour écrire les tests unitaires d'une méthode testée.

  • La section Arrange d'une méthode de test unitaire initialise les objets et définit la valeur des données transmises à la méthode testée.

  • La section Act appelle la méthode testée avec les paramètres triés.

  • La section Assert vérifie que l'action de la méthode testée se comporte comme prévu.

Pour tester la méthode CheckingAccount.Withdraw de notre exemple, nous pouvons écrire deux tests : l'un qui vérifie le comportement standard de la méthode et l'autre qui vérifie qu'un retrait supérieur au solde échouera.Dans la classe CheckingAccountTests, nous ajoutons les méthodes suivantes :

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;
    var account = new CheckingAccount("JohnDoe", currentBalance);
    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;
    // assert
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Withdraw_AmountMoreThanBalance_Throws()
{
    // arrange
    var account = new CheckingAccount("John Doe", 10.0);
    // act
    account.Withdraw(1.0);
    // assert is handled by the ExpectedException
}

notez que Withdraw_ValidAmount_ChangesBalance utilise une instruction Assert explicite pour déterminer si la méthode de test réussit ou échoue, tandis que Withdraw_AmountMoreThanBalance_Throws utilise l'attribut ExpectedException pour déterminer la réussite de la méthode testée.En coulisses, une infrastructure de test unitaire encapsule les méthodes de test dans les instructions try/catch.Dans la plupart des cas, si une exception est interceptée, la méthode de test échoue et l'exception est ignorée.L'attribut ExpectedException entraîne la réussite de la méthode de test si l'exception spécifiée est levée.

Pour plus d'informations sur les infrastructures de tests unitaires Microsoft, consultez l'une des rubriques suivantes :

Définition des délais d'expiration

Pour définir un délai d'expiration sur une méthode de test :

[TestMethod]
[Timeout(2000)]  // Milliseconds
public void My_Test()
{ ...
}

Pour définir le délai d'expiration à la valeur maximale autorisée :

[TestMethod]
[Timeout(TestTimeout.Infinite)]  // Milliseconds
public void My_Test ()
{ ...
}

Exécution des tests dans l'Explorateur de tests

Lorsque vous générez le projet de test, les tests s'affichent dans l'Explorateur de tests.Si l'Explorateur de tests n'est pas visible, sélectionnez Test dans le menu Visual Studio et choisissez Fenêtres, puis Explorateur de tests.

Explorateur de tests unitaires

Tandis que vous exécutez, écrivez et réexécutez vos tests, par défaut l'Explorateur de tests affiche les résultats par groupes : Tests échoués, Tests réussis, Tests ignorés et Tests non exécutés.Vous pouvez choisir un en-tête de groupe pour ouvrir la vue qui affiche tous les tests de ce groupe.

Exécution et affichage des tests à partir de la barre d'outils de l'Explorateur de tests

La barre d'outils de l'Explorateur de tests vous permet de découvrir, d'organiser et d'exécuter les tests qui vous intéressent.

Exécuter des tests à partir de la barre d'outils de l'explorateur de tests

Vous pouvez choisir Exécuter tout pour exécuter tous vos tests ou Exécuter pour sélectionner un sous-ensemble de tests à exécuter.Après que vous avez exécuté un ensemble de tests, un résumé de la série de tests s'affiche en bas de la fenêtre Explorateur de tests.Sélectionnez un test pour en afficher les détails dans le volet inférieur.Choisissez Ouvrir un Test dans le menu contextuel (ou F12) pour afficher le code source du test sélectionné.

Exécution des tests après chaque build

Mise en gardeAttention

L'exécution de tests unitaires après chaque build est prise en charge uniquement dans Visual Studio Ultimate.

Exécuter après les builds

Pour exécuter vos tests unitaires après chaque build locale, choisissez Test dans le menu standard, puis Exécuter les tests après la génération dans la barre d'outils de l'Explorateur de tests.

Filtrage et regroupement de la liste de tests

Lorsque vous avez un grand nombre de tests, vous pouvez entrer une chaîne dans la zone de recherche de l'Explorateur de tests pour filtrer la liste sur la chaîne spécifiée.Vous pouvez limiter votre filtre encore plus en choisissant parmi la liste des filtres.

Rechercher des catégories de filtre

Bouton du groupe d'explorateur de tests

Pour regrouper vos tests par catégorie, choisissez le bouton Grouper par.

Pour plus d'informations, consultez Exécution de tests unitaires avec Test Explorer

Débogage des tests unitaires

Vous pouvez utiliser l'Explorateur de tests pour démarrer une session de débogage de vos tests.L'exécution pas à pas de votre code avec le débogueur Visual Studio vous conduit de manière transparente à des allers et retours entre les tests unitaires et le projet testé.Pour démarrer le débogage :

  1. Dans l'éditeur de Visual Studio, définissez un point d'arrêt dans une ou plusieurs méthodes de test que vous souhaitez déboguer.

    [!REMARQUE]

    Comme les méthodes de test peuvent s'exécuter dans n'importe quel ordre, définissez les points d'arrêt dans toutes les méthodes de test que vous souhaitez déboguer.

  2. Dans l'Explorateur de tests, sélectionnez les méthodes de test, puis choisissez Déboguer les tests sélectionnés dans le menu contextuel.

Pour plus d'informations sur le débogueur, consultez Débogage dans Visual Studio.

Outils supplémentaires pour les tests unitaires

Génération du code d'application à partir des tests

Si vous écrivez vos tests avant d'écrire le code de votre projet, vous pouvez utiliser IntelliSense pour générer les classes et les méthodes dans le code de votre projet.Écrivez une instruction dans une méthode de test qui appelle la classe ou la méthode que vous souhaitez générer, puis ouvrez le menu IntelliSense sous l'appel.Si l'appel concerne un constructeur de la nouvelle classe, choisissez Générer un nouveau type dans le menu et suivez l'Assistant pour insérer la classe dans le code de votre projet.Si l'appel concerne une méthode, choisissez Générer une nouvelle méthode à partir du menu IntelliSense.

Menu Intellisense de génération de stub de méthode

Génération de plusieurs tests à l'aide de méthodes de test pilotées par les données

[!REMARQUE]

Ces procédures s'appliquent uniquement pour tester les méthodes que vous écrivez à l'aide de l'infrastructure de tests unitaires Microsoft pour le code managé.Si vous utilisez une autre infrastructure, consultez la documentation de cette dernière pour obtenir des fonctionnalités équivalentes.

Les méthodes de test pilotées par les données vous permettent de vérifier une plage de valeurs dans une méthode de test unitaire.Pour créer une méthode de test unitaire pilotée par des données, complétez la méthode avec un attribut DataSource qui spécifie la source de données et la table contenant les valeurs des variables que vous voulez tester.Dans le corps de la méthode, vous affectez les valeurs de ligne aux variables à l'aide de l'indexeur TestContext.DataRow[ColumnName].

Par exemple, supposons que nous ajoutions une méthode superflue à la classe CheckingAccount nommée AddIntegerHelper.AddIntegerHelper ajoute deux entiers.

Pour créer un test piloté par les données pour la méthode AddIntegerHelper, nous créons d'abord une base de données Access intitulée AccountsTest.accdb et une table nommée AddIntegerHelperData.La table AddIntegerHelperData définit les colonnes pour spécifier les premier et deuxième opérandes de l'addition, et une colonne pour spécifier le résultat attendu.Nous remplissons un certain nombre de lignes avec les valeurs appropriées.

    [DataSource(
        @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Projects\MyBank\TestData\AccountsTest.accdb", 
        "AddIntegerHelperData"
    )]
    [TestMethod()]
    public void AddIntegerHelper_DataDrivenValues_AllShouldPass()
    {
        var target = new CheckingAccount();
        int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
        int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]); 
        int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
        int actual = target.AddIntegerHelper(x, y);
        Assert.AreEqual(expected, actual);
    }

La méthode attribuée s'exécute une fois pour chaque ligne de la table.L'Explorateur de tests indique un échec du test de la méthode si l'une des itérations échoue.Le volet Détails des résultats du test de la méthode vous indique le statut réussite/échec pour chaque ligne de données.

Pour plus d'informations, consultez Comment : créer un test unitaire piloté par des données

Analyse de la couverture du code de test unitaire

[!REMARQUE]

La couverture du code de test unitaire est disponible pour tous les langages natifs et managés et toutes les infrastructures de tests unitaires qui peuvent être exécutés par l'infrastructure des tests unitaires.

Vous pouvez déterminer la quantité de code de votre produit qui est réellement testée par vos tests unitaires à l'aide de l'outil de couverture de code Visual Studio.Vous pouvez exécuter la couverture de code sur les tests sélectionnés ou sur tous les tests d'une solution.La fenêtre Résultats de la couverture du code affiche le pourcentage des blocs du code du produit qui ont été testés par ligne, fonction, classe, espace de noms et module.

Pour exécuter la couverture du code pour les méthodes de test d'une solution,

  1. choisissez Tests dans le menu Visual Studio, puis Analyser la couverture du code.

  2. Choisissez l'une des commandes suivantes :

    1. Tests sélectionnés exécute les méthodes de test que vous avez sélectionnées dans l'Explorateur de tests.

    2. Tous les tests exécute toutes les méthodes de test de la solution.

Les résultats de la couverture apparaissent dans la fenêtre Résultats de la couverture du code.

Résultats de la couverture du code

Pour plus d'informations, consultez Utilisation de la couverture du code pour déterminer la quantité de code testé.

Isolation des méthodes de test unitaire avec Microsoft Fakes

[!REMARQUE]

Microsoft Fakes est disponible uniquement dans Visual Studio Ultimate.Microsoft Fakes peut être utilisé uniquement avec les méthodes de test que vous écrivez à l'aide des infrastructures de tests unitaires pour le code managé.

Le problème

Les méthodes de test unitaire qui se concentrent sur la vérification du code interne d'une fonction peuvent être difficiles à écrire lorsque la méthode de test appelle des fonctions qui présentent des dépendances externes.Par exemple, les méthodes de l'exemple de classe CheckingAccount doivent probablement effectuer des appels au composant BankDb pour mettre à jour la base de données principale.Nous pouvons refactoriser la classe CheckingAccount pour qu'elle se présente ainsi :

class CheckingAccount : IAccount
{
    public CheckingAccount(customerName, double startingBalance, IBankDb bankDb)
    {
        m_bankDb = bankDb;
        // set up account
    }

    public void Withdraw(double amount)
    {
        if(m_balance >= amount)
        {
            m_balance = m_MyBankDb.Withdraw(m_accountInfo.ID, amount);
        }
        else
        {
            throw new ArgumentException(amount, "Withdrawal exceeds balance!")
        }
    }

    private IBankDb m_bankDb = null;
    // ...

Les tests unitaires de cette méthode CheckingAccount.Withdraw peuvent échouer en raison des problèmes provoqués par l'appel à m_bankDb.Withdraw.La connexion à la base de données ou au réseau peut être perdue ou les autorisations sur la base de données peuvent être erronées.Une défaillance dans l'appel de m_bankDB.Withdraw provoque l'échec du test pour des raisons qui ne sont pas liées à son code interne.

La solution Microsoft Fakes

Microsoft Fakes crée un assembly qui contient les classes et les méthodes que vous pouvez remplacer pour les classes des méthodes de test unitaire qui provoquent des dépendances.Une classe de substitution dans le module Fakes généré déclare une méthode et un délégué pour chaque méthode publique du composant cible.Dans une méthode de test, vous implémentez le délégué pour créer le comportement exact de l'appel de dépendance dans la méthode que vous souhaitez tester.

Dans notre exemple, nous pouvons créer un assembly Fakes pour le projet BankDb, puis utiliser la classe StubIBankDb générée par Fakes et qui dérive de l'interface IBankDb pour supprimer l'incertitude provoquée par les interactions avec la base de données.Une version modifiée de la méthode de test Withdraw_ValidAmount_ChangesBalance se présenterait alors ainsi :

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;

    // set up the Fakes object and delegate
    var stubBankDb = new MyBank.Stubs.StubIBankDb();
    stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }
    var account = new CheckingAccount("JohnDoe", currentBalance, stubBankDb);

    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;

    // assert
    Assert.AreEqual(expected, actual);
}

Cette ligne dans la méthode de test :

stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }

implémente le délégué Fakes pour la méthode Withdraw à l'aide d'une expression lamba.La méthode stubBankDb.Withdraw appelle le délégué et ainsi retourne toujours le montant spécifié, ce qui permet à la méthode de test de vérifier de façon fiable le comportement de la méthode Accounts.

En savoir plus sur Microsoft Fakes

Microsoft Fakes utilise deux approches pour créer les classes de substitution :

  1. Les stubs génèrent des classes de substitution dérivées de l'interface parente de la classe de dépendance cible.Les méthodes stub peuvent être remplacées par des méthodes virtuelles publiques de la classe cible.

  2. Les shims utilisent l'instrumentation du runtime pour rediriger les appels à une méthode cible vers une méthode shim de substitution pour les méthodes non virtuelles.

Dans les deux approches, vous utilisez les délégués générés des appels à la méthode de dépendance pour spécifier le comportement souhaité dans la méthode de test.

Pour plus d'informations, consultez Isolation du code sous test avec Microsoft Fakes.