Tests unitaires du code natif avec Test Explorer
Dans Visual Studio, vous pouvez créer des tests unitaires pour le code non managé écrit en C++.Code non managé est parfois appelé code natif.
La procédure suivante contient les informations nécessaires pour vous permettre de démarer.Les sections suivantes fournissent une procédure pas - à - pas qui décrit les étapes en détail.
Pour écrire des tests unitaires pour une DLL de code non managé
Utilisez le modèle projet de test natif pour créer un projet Visual Studio distinct pour vos tests.
Le projet contient du code de test d'exemple.
Rendez la DLL accessible au projet de test :
#include un fichier .h qui contient des déclarations de fonctions extérieurement accessibles à partir de la DLL.
Le fichier .h doit contenir des déclarations de fonction marquées avec _declspec(dllimport).Sinon, vous pouvez exporter des méthodes à l'aide d'un fichier de DEF.Pour plus d'informations, consultez Importation et exportation.
Vos tests unitaires peuvent accéder uniquement aux fonctions exportées à partir de la DLL testée.
Ajoutez le projet de DLL aux références du projet de test :
Dans Propriétés du projet de test, développez Propriétés communes, infrastructure et références, puis choisissez Ajouter une référence.
Dans le projet de test, créez les classes et les méthodes de test à l'aide de les macros d'ESSAI et déclarez la classe de la manière suivante :
#include "stdafx.h" #include <CppUnitTest.h> #include "..\MyProjectUnderTest\MyCodeUnderTest.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; TEST_CLASS(TestClassName) { public: TEST_METHOD(TestMethodName) { // Run a function under test here. Assert::AreEqual(expectedValue, actualValue, L"message", LINE_INFO()); } }
Assert contient plusieurs fonctions statiques que vous pouvez utiliser pour vérifier le résultat d'un test.
Le paramètre LINE_INFO() est optionnel.Dans les cas où il n'existe aucun fichier PDB, il permet au testeur d´identifier l'emplacement d'un échec.
Vous pouvez également écrire des méthodes d'installation et de nettoyage de test.Pour plus d'informations, ouvrez la définition de la macro TEST_METHOD , puis lisez les commentaires dans CppUnitTest.h
Vous ne pouvez pas imbriquer des classes de test.
Explorateur de tests à utiliser pour exécuter les tests :
Dans le menu Affichage, choisissez Autres fenêtres, explorateur de tests.
Générez la solution Visual Studio.
Dans lExplorateur de tests, choissisez Tout executer
Pour examiner un test plus en détail dans l'explorateur de tests :
Sélectionnez le nom du test pour afficher plus de détails tels qu'un message et une trace de la pile d'échec.
Ouvrez le nom du test (par exemple en double-cliquant) pour accéder à l'emplacement d'échec ou au code de test.
Dans le menu contextuel pour un test, choisissez Déboguer le test sélectionné pour exécuter le test dans le débogueur.
Procédure pas - à - pas : Développer une DLL non managée à l'explorateur de tests
Vous pouvez adapter cette procédure pas - à - pas pour développer votre propre DLL.Les étapes principales sont les suivantes.
créez un projet de test natif.Les tests sont créés dans un projet séparé de la DLL que vous développez.
Créerun project de DLLCette procédure pas - à - pas crée une DLL, mais la procédure pour tester une DLL existante est similaire.
Rendez les fonctions DLL visibles par les tests.
Augmentez de manière itérative des tests.Nous recommandons le cycle « red-green-refactor », dans lequel le développement du code est mené par les tests.
Tests ont échoué le Debug.Vous pouvez exécuter des tests en mode débogage.
Refactoriser tout en conservant les tests pas affectés.Refactoriser signifie améliorer la structure du code sans modifier son comportement externe.Vous pouvez le faire pour améliorer les performances, extensibilité, ou la lisibilité du code.Étant donné que l'objectif n'est pas de modifier le comportement, vous ne modifiez pas les tests en apportant une modification de refactorisation du code.L'utilisation de tests permet de vérifier que vous n´introduisez pas de bogues lorsque vous refactorisez.Vous pouvez donc effectuer de telles modifications avec beaucoup plus de confiance que si vous n'aviez pas de tests.
Vérifiez la couverture.Les tests unitaires sont plus utiles lorsqu'ils utilisent plus de votre code.Vous pouvez découvrir quelles parties de votre code ont été utilisées par les tests.
Unités à isoler des ressources externes.En général, une DLL dépend d'autres parties du système que vous développez, tel que d'autres DLL, les bases de données, ou des sous-systèmes distants.Il est utile de tester chaque unité de manière isolée de ses dépendances.Les composants externes peuvent effectuer le test lentement.Pendant le développement, les autres composants peuvent ne pas être complets.
Créer un projet de test unitaire natif.
Dans le menu Fichier, cliquez sur Nouveau, Projet.
Dans la boîte de dialogue, développez Installé, Modèles, Visual C++, Test.
Sélectionnez le modèle projet de test natif .
Dans cette procédure pas - à - pas, le projet de test est nommé NativeRooterTest.
Dans le nouveau projet, examinez unittest1.cpp
Notez que :
Chaque test est défini en utilisant TEST_METHOD(YourTestName){...}
Vous ne devez pas écrire une signature de fonction classique.La signature est créée par la macro TEST_METHOD.La macro génère une fonction d'instance qui retourne void.Il génère également une fonction statique qui retourne des informations sur la méthode de test.Ces informations permettent à l'explorateur de tests de rechercher la méthode.
Les méthodes de test sont groupées en classes en utilisant TEST_CLASS(YourClassName){...}.
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 Organiser des tests C++.
Vérifiez que les tests sont lancés dans l'explorateur de tests :
Insérez un code de test :
TEST_METHOD(TestMethod1) { Assert::AreEqual(1,1); }
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 , Tous les tests.
Les tests sont construits et exécutés.
L'explorateur de tests s'affiche.
Le test s'affiche sous Tests réussis.
Créez un projet de DLL non managée
Créez un projet Visual C++ à l'aide du modèle Projet Win32 .
Dans cette procédure pas - à - pas, le projet est nommé RootFinder.
Sélectionnez DLL et symboles d'exportation dans l'Assistant Application Win32.
L'option Exporte les symboles génère une macro pratique que vous pouvez utiliser pour déclarer des méthodes exportées.
Déclarez une fonction exportée dans le fichier .h principal:
Le déclarateur __declspec(dllexport) rend le public et les membres protégés de la classe visibles à l'extérieur de la DLL.Pour plus d'informations, consultez À l'aide de dllimport et le dllexport dans les classes C++.
Dans le fichier .cpp principal, ajoutez un corps minimal pour la fonction :
// Find the square root of a number. double CRootFinder::SquareRoot(double v) { return 0.0; }
Couplez le projet de test dans le projet de DLL
Ajoutez le projet de DLL aux références de projet du projet de test :
Ouvrez les propriétés du projet de test et choisissez Propriétés communes, infrastructure et références.
Choisissez Ajouter une nouvelle référence.
Dans la boîte de dialogue Ajouter une référence , sélectionnez le projet de DLL et choisissez Ajouter.
Dans le fichier .cpp principal de test unitaire, incluez le fichier .h du code de la DLL :
#include "..\RootFinder\RootFinder.h"
Ajoutez un test de base qui utilise la fonction exportée :
TEST_METHOD(BasicTest) { CRootFinder rooter; Assert::AreEqual( // Expected value: 0.0, // Actual value: rooter.SquareRoot(0.0), // Tolerance: 0.01, // Message: L"Basic test failed", // Line number - used if there is no PDB file: LINE_INFO()); }
Générez la solution.
Le nouveau test s'affiche dans l'explorateur de tests.
Dans lExplorateur de tests, choissisez Tout executer
Vous avez installé le test et les projets de code, et vérifié que vous pouvez exécuter des tests qui exécutent des fonctions dans le projet de code.Vous pouvez maintenant commencer à écrire de vrais tests et du code.
De manière itérative augmentez les tests et faites les passer
Ajoutez un nouveau test :
TEST_METHOD(RangeTest) { CRootFinder rooter; for (double v = 1e-6; v < 1e6; v = v * 3.2) { double actual = rooter.SquareRoot(v*v); Assert::AreEqual(v, actual, v/1000); } }
Conseil Nous vous conseillons de ne pas modifier les tests qui ont réussi.À la place, ajoutez 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 appropriés.Entrez les nouveaux tests et faites-les s´exécuter un par un, de la même façon incrémentielle.
Générez la solution, puis dans l'explorateur de tests, sélectionnez Exécuter tout.
Les nouveaux tests échouent.
Conseil Vérifiez que chaque test échoue immédiatement après que vous l'avez écrit.Cela permet d'éviter l'erreur facile d'écrire un test qui n'échoue jamais.
Améliorer le code sous test afin que le test réussisse :
#include <math.h> ... double CRootFinder::SquareRoot(double v) { double result = v; double diff = v; while (diff > result/1000) { double oldResult = result; result = result - (result*result - v)/(2*result); diff = abs (oldResult - result); } return result; }
Générez la solution puis dans l'explorateur de tests, sélectionnez Exécuter tout.
Les deux tests passent.
Conseil Développez le code en ajoutant des tests un par un.Assurez -vous que tous les tests réussissent après chaque itération.
Déboguez un test qui a échoué
Ajoutez un autre test :
#include <stdexcept> ... // Verify that negative inputs throw an exception. TEST_METHOD(NegativeRangeTest) { wchar_t message[200]; CRootFinder rooter; for (double v = -0.1; v > -3.0; v = v - 0.5) { try { // Should raise an exception: double result = rooter.SquareRoot(v); _swprintf(message, L"No exception for input %g", v); Assert::Fail(message, LINE_INFO()); } catch (std::out_of_range ex) { continue; // Correct exception. } catch (...) { _swprintf(message, L"Incorrect exception for %g", v); Assert::Fail(message, LINE_INFO()); } } }
Générez la solution et sélectionnez Exécuter tout.
Ouvrez (ou double-cliquez) sur le test qui a échoué.
L'assertion erronée est mise en surbrillance.Le message d'erreur est visible dans le volet d'informations de l'explorateur de tests.
Pour voir pourquoi le test échoue, parcourir la fonction :
Définissez un point d'arrêt au début de la fonction de SquareRoot.
Dans le menu contextuel du test, choisissez Déboguer les tests sélectionnés.
Lorsque l'exécution s'arrête au point d'arrêt, parcourez le code.
Insérez le code dans la fonction que vous développez :
#include <stdexcept> ... double CRootFinder::SquareRoot(double v) { // Validate parameter: if (v < 0.0) { throw std::out_of_range("Can't do square roots of negatives"); }
Tous les tests réussissent maintenant.
Refactorisez le code sans modifier de tests
Simplifiez le calcul central dans la fonction de SquareRoot :
// old code: // result = result - (result*result - v)/(2*result); // new code: result = (result + v/result)/2.0;
Générez la solution et sélectionnez Exécuter tout, pour vous assurer que vous n'avez pas introduit une erreur.
Conseil Un bon jeu de tests unitaires donne confiance que vous n'avez pas introduit des bogues lorsque vous modifiez le code.
Conservez la refactorisation séparées d'autres modifications.
Étapes suivantes
Isolement La plupart des DLL dépendent d'autres sous-systèmes tels que des bases de données et d'autres DLL.Ces autres composants sont souvent développés en parallèle.Pour permettre au test unitaire de s' exécuter alors que les autres composants ne sont pas encore disponibles, vous devez substituer la simulation ou
test de vérification de build (BVT) Vous pouvez avoir des tests exécutés sur le serveur de builds de votre équipe à des intervalles définis.Cela garantit que les bogues ne sont pas introduits lorsque le travail de plusieurs membres de l'équipe est intégré.
Tests de Checkin. Vous pouvez exiger que certains tests soient exécutés avant que chaque membre de l'équipe contrôle le code dans le contrôle de code source.En général c'est un sous-ensemble du jeu complet de tests de vérification de build.
Vous pouvez également avoir besoin d'un niveau minimum de couverture du code.
Voir aussi
Tâches
Walkthrough: Creating and Using a Dynamic Link Library (C++)
Concepts
Autres ressources
Une vue d'ensemble de l'interopérabilité de code managée/non managé