Test unitaire du code Visual C# dans une application du Windows Store
Cette rubrique décrit une méthode de création de tests unitaires pour une classe Visual C# dans une application Windows Store à l'aide de Visual Studio Express 2012 pour Windows 8 et de l'infrastructure de test unitaire Microsoft. La classe Rooter illustre de vagues souvenirs de la théorie de limite du calcul en implémentant une fonction qui calcule une estimation de la racine carrée d'un nombre donné. L'application Maths peut ensuite utiliser cette fonction pour montrer à l'utilisateur les activités ludiques que l'on peut faire avec les mathématiques.
Cette rubrique explique comment utiliser le test unitaire comme première étape du développement. Dans cette approche, vous écrivez d'abord une méthode de test qui vérifie un comportement spécifique dans le système que vous testez, puis vous écrivez le code qui réussit le test. En modifiant l'ordre des procédures suivantes, vous pouvez inverser cette stratégie de manière à écrire d'abord le code que vous souhaitez tester, puis à écrire les tests unitaires.
Cette rubrique crée également une solution Visual Studio unique et des projets distincts pour les tests unitaires et la DLL que vous souhaitez tester. Vous pouvez également inclure les tests unitaires directement dans le projet DLL, ou vous pouvez créer des solutions distinctes pour les tests unitaires et la DLL.
Notes
Visual Studio Ultimate, VS Premium et VS Professional fournissent des fonctionnalités de test unitaire supplémentaires.
-
VS Ultimate, VS Premium et VS Professional vous permettent d'utiliser une infrastructure de test unitaire tierce et open source qui a créé un adaptateur complémentaire pour l'explorateur de tests Microsoft. Vous pouvez également analyser et afficher les informations de couverture du code pour les tests.
-
VS Ultimate et VS Premium vous permettent d'exécuter vos tests après chaque génération.
-
VS Ultimate contient également Microsoft Fakes, une infrastructure d'isolement pour le code managé, qui vous permet de concentrer vos tests sur votre propre code en remplaçant le code de test pour les fonctionnalités du système et tierces.
Pour plus d'informations, consultez Verifying Code by Using Unit Tests dans MSDN Library.
Dans cette rubrique
Créer la solution et le projet de test unitaire
Vérifier l'exécution des tests dans l'explorateur de tests
Ajouter la classe Rooter au projet Maths
Associer le projet de test au projet d'application
Augmenter itérativement les tests et les faire réussir
Déboguer un test échoué
Refactoriser le code
Créer la solution et le projet de test unitaire
Dans le menu Fichier, choisissez Nouveau, puis Nouveau projet.
Dans la boîte de dialogue Nouveau projet, développez Installé, Visual C#, puis choisissez Windows Store. Choisissez ensuite Application vide dans la liste de modèles de projet.
Nommez le projet Maths et vérifiez que Créer le répertoire pour la solution est sélectionné.
Dans l'explorateur de solutions, sélectionnez le nom de la solution, Ajouter dans le menu contextuel, puis Nouveau projet.
Dans la boîte de dialogue Nouveau projet, développez Installé, Visual C#, puis choisissez Windows Store. Choisissez ensuite Bibliothèque de tests unitaires (applications Windows Store) dans la liste des modèles de projet.
Ouvrez UnitTest1.cs dans l'éditeur Visual Studio.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; using Maths; namespace RooterTests { [TestClass] public class UnitTest1 [TestMethod] public void TestMethod1() { }
Prenez note de ce qui suit :
Chaque test est défini à l'aide de [TestMethod]. Une méthode de test doit retourner void et ne contient pas de paramètres.
Les méthodes de test doivent figurer dans une classe décorée avec l'attribut [TestClass].
Lorsque les tests sont exécutés, une instance de chaque classe de test est créée. Les méthodes de test sont appelées dans un ordre non spécifié.
Vous pouvez définir des méthodes spéciales qui sont appelées avant et après chaque module, classe ou méthode. Pour plus d'informations, consultez Utilisation des membres Microsoft.VisualStudio.TestTools.UnitTesting dans les tests unitaires dans MSDN Library.
Vérifier l'exécution des tests dans l'explorateur de tests
Insérez du code de test dans TestMethod1 du fichier UnitTest1.cs :
[TestMethod] public void TestMethod1() { Assert.AreEqual(0, 0); }
Notez que la classe Assert fournit plusieurs méthodes statiques que vous pouvez utiliser pour vérifier les résultats dans les méthodes de test.
Dans le menu Test, choisissez Exécuter, puis Exécuter tout.
Le projet de test est généré et exécuté. La fenêtre de l'explorateur de tests s'affiche, et le test est répertorié sous Tests réussis. Le volet de résumé situé au bas de la fenêtre fournit des informations supplémentaires sur le test sélectionné.
Ajouter la classe Rooter au projet Maths
Dans l'explorateur de solutions, sélectionnez le nom de projet Maths. Dans le menu contextuel, sélectionnez Ajouter, puis Classe.
Nommez le fichier de classe Rooter.cs.
Ajoutez le code suivant au fichier Rooter.cs de la classe Rooter :
public Rooter() { } // estimate the square root of a number public double SquareRoot(double x) { return 0.0; }
La classe Rooter déclare un constructeur et la méthode d'estimation SqareRoot.
La méthode SqareRoot n'est qu'une implémentation minimale, qui est suffisante pour tester la structure de base de la configuration de test.
Associer le projet de test au projet d'application
Ajoutez une référence de l'application Maths au projet RooterTests.
Dans l'explorateur de solutions, sélectionnez le projet RooterTests, puis Ajouter une référence... dans le menu contextuel.
Dans la boîte de dialogue Ajouter une référence - RooterTests, développez Solution, puis choisissez Projets. Sélectionnez ensuite l'élément Maths.
Ajoutez une instruction using au fichier UnitTest1.cs :
Ouvrez UnitTest1.cs.
Ajoutez le code suivant sous la ligne using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; :
using Maths;
Ajoutez un test qui utilise la fonction Rooter. Ajoutez le code suivant à UnitTest1.cpp :
[TestMethod] public void BasicTest() { Maths.Rooter rooter = new Rooter(); double expected = 0.0; double actual = rooter.SquareRoot(expected * expected); double tolerance = .001; Assert.AreEqual(expected, actual, tolerance); }
Générez la solution.
Le nouveau test s'affiche dans l'explorateur de tests dans le nœud Tests non exécutés.
Dans l'explorateur de tests, sélectionnez Exécuter tout.
Vous avez configuré le test et les projets de code, et vérifié qu'il est possible d'exécuter des tests qui exécutent des fonctions dans le projet de code. Vous pouvez maintenant commencer à écrire des tests et du code réels.
Augmenter itérativement les tests et les faire réussir
Ajoutez un nouvel test :
[TestMethod] public void RangeTest() { Rooter rooter = new Rooter(); for (double v = 1e-6; v < 1e6; v = v * 3.2) { double expected = v; double actual = rooter.SquareRoot(v*v); double tolerance = ToleranceHelper(expected); Assert.AreEqual(expected, actual, tolerance); } }
Conseil
Nous vous recommandons de ne pas modifier les tests qui ont réussi. Ajoutez plutôt un nouveau test, mettez à jour le code afin que le test réussisse, puis ajoutez un autre test, et ainsi de suite.
Lorsque les utilisateurs modifient leurs spécifications, désactivez les tests qui ne sont plus corrects. Écrivez de nouveaux tests et exécutez-les individuellement, de la même façon incrémentielle.
Dans l'explorateur de tests, sélectionnez Exécuter tout.
Le test échoue.
Conseil
Immédiatement après l'avoir écrit, vérifiez que chaque test échoue. Cela permet d'éviter l'erreur facile d'écrire un test qui n'échoue jamais.
Améliorez le code testé afin que le nouveau test réussisse. Remplacez la fonction SqareRoot dans Rooter.cs par ce qui suit :
public double SquareRoot(double x) { double estimate = x; double diff = x; while (diff > estimate / 1000) { double previousEstimate = estimate; estimate = estimate - (estimate * estimate - x) / (2 * estimate); diff = Math.Abs(previousEstimate - estimate); } return estimate; }
Générez la solution, puis sélectionnez Exécuter tout dans l'explorateur de tests.
Les trois tests réussissent maintenant.
Conseil
Développez le code en ajoutant les tests individuellement. Vérifiez que tous les tests réussissent après chaque itération.
Déboguer un test échoué
Ajoutez un autre test à UnitTest1.cs :
// Verify that negative inputs throw an exception. [TestMethod] public void NegativeRangeTest() { string message; Rooter rooter = new Rooter(); for (double v = -0.1; v > -3.0; v = v - 0.5) { try { // Should raise an exception: double actual = rooter.SquareRoot(v); message = String.Format("No exception for input {0}", v); Assert.Fail(message); } catch (ArgumentOutOfRangeException ex) { continue; // Correct exception. } catch (Exception e) { message = String.Format("Incorrect exception for {0}", v); Assert.Fail(message); } } }
Dans l'explorateur de tests, sélectionnez Exécuter tout.
Le test échoue. Sélectionnez le nom du test dans l'explorateur de tests. L'assertion échouée est mise en surbrillance. Le message d'échec est visible dans le volet de détails de l'explorateur de tests.
Pour comprendre pourquoi le test échoue, parcourez la fonction :
Définissez un point d'arrêt au début de la fonction SquareRoot.
Dans le menu contextuel du test échoué, choisissez Déboguer les tests sélectionnés.
Lorsque l'exécution s'arrête au point d'arrêt, parcourez le code.
Ajoutez le code à la méthode Rooter pour intercepter l'exception :
public double SquareRoot(double x) { if (x < 0.0) { throw new ArgumentOutOfRangeException(); }
- Dans l'explorateur de tests, sélectionnez Exécuter tout pour tester la méthode corrigée et vérifier que vous n'avez pas créé une régression.
Tous les tests réussissent maintenant.
Refactoriser le code
Simplifiez le calcul central dans la fonction SquareRoot.
Modifiez l'implémentation du résultat.
// old code //result = result - (result*result - v)/(2*result); // new code result = (result + v/result) / 2.0;
Choisissez Exécuter tout pour tester la méthode refactorisée et vérifier que vous n'avez pas créé une régression.
Conseil
Un ensemble stable de tests unitaires corrects est l'assurance que vous n'avez pas créé de bogues lors de la modification du code.
Refactorisez le code de test pour supprimer le code dupliqué.
Notez que la méthode RangeTest code en dur le dénominateur de la variable de tolérance utilisée dans la méthode Assert. Si vous prévoyez d'ajouter des tests supplémentaires qui utilisent le même calcul de tolérance, l'utilisation d'une valeur codée en dur dans plusieurs emplacements peut provoquer des erreurs.
Ajoutez une méthode privée à la classe Unit1Test pour calculer la valeur de tolérance, puis appelez cette méthode à la place.
private double ToleranceHelper(double expected) { return expected / 1000; } ... [TestMethod] public void RangeTest() { ... // old code // double tolerance = expected/1000; // new code double tolerance = ToleranceHelper(expected); Assert.AreEqual(expected, actual, tolerance); } ...
Choisissez Exécuter tout pour tester la méthode refactorisée et vérifier que vous n'avez pas créé une erreur.
Notes
Pour ajouter une méthode d'assistance à une classe de test, n'ajoutez pas l'attribut [TestMethod] à la méthode. L'explorateur de tests n'enregistre pas la méthode à exécuter.