Utilisation de GoogleTest pour les tests unitaires d'une application C++

Table des matières

1 Introduction

GoogleTest est une bibliothèque de tests unitaires qui facilite leur écriture et leur passage. Si sa prise en main peut sembler une perte de temps au démarrage d'un projet, son utilisation permet ensuite d'améliorer la qualité des développements en permettant la remontée de bugs au plus tôt, voire le TDD (Test-Driven Development), technique de développement dans laquelle le développeur commence par écrire les tests, puis écrit son code.

Il existe de nombreuses bibliothèques de tests unitaires :

Dans le cadre de ce cours C++, nous vous proposons d'utiliser GoogleTest car il est de très bonne facture, a une communauté d'utilisateurs nombreuse, et offre une bonne intégration avec Visual Studio et Xcode.

Cette page est une introduction à GoogleTest et à son utilisation dans Visual Studio.

2 Exemple d'un fichier de test GoogleTest

Supposons que vous souhaitiez tester deux fonctions que vous avez écrites : une fonction qui calcule la factorielle d'un nombre et une fonction qui détermine si un nombre est un carré parfait ou non. Voici un exemple de test unitaire écrit avec GoogleTest :

#include "gtest/gtest.h"
#include "declarationsDeVosFonctions.h"

TEST(Exemple1, Factorielle)
{
	EXPECT_EQ(1, factorielle(-1));
	EXPECT_EQ(1, factorielle(0));
	EXPECT_EQ(6, factorielle(3));
}

TEST(Exemple1, CarreParfait)
{
	EXPECT_FALSE(estUnCarreParfait(-2));
	EXPECT_TRUE(estUnCarreParfait(0));
	EXPECT_TRUE(estUnCarreParfait(4));
	EXPECT_FALSE(estUnCarreParfait(8));
}

Pour de plus amples informations sur les primitives offertes par GoogleTest pour vos tests, lire la section Assertions de https://github.com/google/googletest/blob/master/googletest/docs/Primer.md

3 Installation de GoogleTest

3.1 Installation de GoogleTest proprement dite

  • Téléchargez l'archive des sources GoogleTest
  • Extrayez le contenu de cet archive si possible dans un répertoire dont le chemin ne contient pas d'espace. dans la suite, nous supposerons que vous avez extrait le contenu dans le répertoire C:\Software
  • Installation au sein de Visual Studio 2017
    • Démarrez Visual Studio.
    • Fichier / Nouveau / Projet... : une fenêtre s'ouvre.
    • Choisissez Projet Win32, indiquez GoogleTestAvecMain au niveau du champ Nom :, vérifiez que le champ Solution : (en bas à gauche) a la valeur "Créer une nouvelle édition", et cliquez sur OK.
    • Une fenêtre d'assistant apparaît : cliquez sur Suivant>
    • Cochez la case Projet vide, sélectionnez Bibliothèque statique, décochez En-tête précompilé, et cliquez sur Terminer.
    • Avec l'explorateur de solutions
      • Si jamais, ils sont présents, supprimez (définitivement) les fichiers stdafx.h, targetver.h et stdafx.cpp
      • Clic-droit sur "Fichiers sources, puis Ajouter / Elément existant… . Une fenêtre s'ouvre : sélectionnez le fichier C:\Software\googletest-master\googletest\src\gtest-all.cc, puis OK
      • Même manipulation pour le fichier C:\Software\googletest-master\googletest\src\gtest-main.cc,
      • Clic droit sur GoogleTestAvecMain, Propriétés.
      • Une fenêtre s'ouvre. Dans la colonne de gauche, sélectionnez C/C++.
      • Dans le champ Autres répertoires Include, mettez C:\Software\googletest-master\googletest;C:\Software\googletest-master\googletest\include Cliquez sur OK
      • Menu Générer / Générer la solution : la génération doit se terminer avec succès.
      • Votre bibliothèque est prête.
  • Installation au sein d'un autre IDE
    • Lisez le fichier C:\Software\googletest-master\googletest\README.md

3.2 Installation de GoogleTestAdapter, le plugin Visual Studio 2017 pour Google Test

  • Fermez Visual Studio
  • Avec un navigateur Web, allez à la page https://marketplace.visualstudio.com/items?itemName=ChristianSoltenborn.GoogleTestAdapter
  • Cliquez sur Download
  • Le navigateur affiche une fenêtre proposant d'ouvrir le fichier GoogleTestAdapter-0.10.1.vsix avec Microsoft Visual Studio Version Selector : cliquez sur OK
  • Une fois l'installation terminée, démarrez Visual Studio.
  • Vous pouvez vérifier que l'installation de l'extension est faite en allant dans le menu Outils / Extensions et mise à jour... : un fenêtre s'ouvre et affiche, notamment l'extension Google Test Adapter

3.3 Installation de GoogleTestAdapter, le plugin Xcode pour Google Test

Le projet https://github.com/mattstevens/xcode-googletest propose deux méthodes pour intégrer Google Test à Xcode. Voir le fichier README.md de ce projet pour voir la démarche à suivre.

4 Utilisation de GoogleTest dans Visual Studio

4.1 Cas d'une solution Visual Studio contenant un projet Win32 (par exemple, une bibliothèque)

4.1.1 Ouverture de votre solution dans Visual Studio

Dans Visual Studio, ouvrez la solution correspondant à votre projet. Dans la suite, nous supposons que votre solution s'appelle MaBibliotheque~.

Par exemple (SVP, déroulez cet exemple si vous n'avez pas de solution contenant une biobliothèque) :

  • Menu Fichier / Nouveau / Projet... : une fenêtre s'ouvre.
  • Choisissez Projet Win32, indiquez MaBibliotheque au niveau du champ Nom :, vérifiez que le champ Solution : (en bas à gauche) a la valeur "Créer une nouvelle édition", et cliquez sur OK.
  • Une fenêtre d'assistant apparaît : cliquez sur Suivant>
  • Cochez la case Projet vide, sélectionnez Bibliothèque statique, décochez En-tête précompilé, et cliquez sur Terminer.
  • Avec l'explorateur de solutions
    • Si jamais, ils sont présents, supprimez (définitivement) les fichiers stdafx.h, targetver.h et stdafx.cpp
    • Clic-droit sur "Fichiers sources, puis Ajouter / Nouvel élément… . Une fenêtre s'ouvre : choisissez Fichier C++, donnez le nom mesFonctionsMathematiques.cpp, et cliquez sur OK. Dans ce fichier source, écrire :
#include "mesFonctionsMathematiques.h"

// NB : Ces deux fonctions contiennent volontairement des erreurs.
//      Si vous ne les voyez pas, GoogleTest vous aidera à les voir.

int factorielle(int const n)
{
	int fact = 1;
	for (int i = 2; i < n; ++i)
		fact *= i;
	return fact;
}

bool estUnCarreParfait(int const n)
{
	int i;
	for (i = 1; i*i < n; ++i);
	return (i*i == n);
}
  • Même manipulation en cliquant droit sur Fichiers sources pour créer mesFonctionsMathematiques.h avec le contenu :
#pragma once
int factorielle(int const n);
bool estUnCarreParfait(int const n);
  • Menu Générer / Générer la solution : la génération doit se terminer avec succès.
  • Votre bibliothèque est prête.

4.1.2 Ajout du projet GoogleTestAvecMain (créé précédemment) à votre solution

  • Menu Fichier / Ajouter> / Projet existant…
  • Naviguez pour sélectionner le fichier GoogleTestAvecMain.vcxproj, puis OK.

4.1.3 Création d'un projet de tests unitaires

  • Menu Fichier / Nouveau / Projet
  • Choisissez Application Console Win32, mettez UnitTests au niveau du champ Nom :, sélectionnez Ajouter à la solution au niveau du champ Solution :, cliquez sur OK. Très important : le nom de votre projet doit se terminer par "Test" ou Tests" (sinon, par la suite, le gestionnaire de tests ne pourra pas trouver vos tests ; cf. explications)
  • Une fenêtre d'assistant s'ouvre : cliquez sur Suivant>
  • Une fenêtre "paramètres de l'application" s'ouvre. Décochez En-tête précompilé", cochez /Projet vide, cliquez sur Terminer.
  • Dans l'explorateur de solutions, clic droit sur fichiers sources du projet TestsUnitaires, Ajouter, Nouvel élément…, Fichier C++ (en lui donnant le nom que vous souhaitez, par exemple testsUnitaires.cpp) et cliquez sur Ajouter
  • Tapez vos tests dans ce fichier. Dans notre exemple (Notez le chemin dans le #include~ de mesFonctionsMathematiques.h):
#include "gtest/gtest.h"
#include "../MaBibliotheque/mesFonctionsMathematiques.h"

TEST(Exemple1, Factorielle)
{
	EXPECT_EQ(1, factorielle(-1));
	EXPECT_EQ(1, factorielle(0));
	EXPECT_EQ(6, factorielle(3));
}

TEST(Exemple1, CarreParfait)
{
	EXPECT_FALSE(estUnCarreParfait(-2));
	EXPECT_TRUE(estUnCarreParfait(0));
	EXPECT_TRUE(estUnCarreParfait(4));
	EXPECT_FALSE(estUnCarreParfait(8));
}
  • Votre projet de tests unitaires a besoin d'accéder aux fichiers d'include de GoogleTest. Donc, clic droit sur UnitTest, Propriétés.
    • Une fenêtre s'ouvre. Dans la colonne de gauche, sélectionnez C/C++.
    • Dans le champ Autres répertoires Include, mettez C:\Software\googletest-master\googletest\include Cliquez sur OK
  • Votre projet de tests unitaires a besoin des références aux 2 autres bibliothèques de cette solution pour que l'édition de liens se fasse :
    • Dans l'explorateur de solutions, clic gauche sur projet UnitTests. Puis, menu Projet / Ajouter une référence….
    • Cochez GoogleTestAvecMain et MaBibliotheque. Cliquez sur OK.
  • Générez la solution : menu Générer / Générer la solution

4.1.4 Exécution des tests

  • Définissez UnitTest comme projet de démarrage : dans l'explorateur de solutions, clic droit sur UnitTests, puis clic gauche sur Définir comme projet de démarrage. NB : si vous oubliez cette étape, Visual Studio affichera une fenêtre pour signaler qu'il ne peut pas démarrer le programme MaBibliotheque.lib (cf. Figure 1).

    erreurQuandOubliDefinitionProjetDeDemarrage image

    Figure 1 : Fenêtre "Impossible de démarrer le programme MaBibliotheque.lib"

  • Exécutez vos tests avec Menu Déboguer / Exécuter sans débogage. Une fenêtre console affiche le résultat du test (cf. Figure 2) :

    sortieConsoleAvecErreurs image

    Figure 2 : Sortie console de GoogleTest

Dit autrement, à la ligne 8 de testsUnitaires.cpp, factorielle(3) renvoie 2 à l'exécution, alors que GoogleTest s'attendait à 6 (grâce à l'instruction EXPECT_EQ(6, factorielle(3));). Et, à la ligne 14, estUnCarreParfait(0) renvoie false au lieu de true (cf. instruction EXPECT_TRUE(estUnCarreParfait(0));)

4.1.5 Exécution des tests avec Google Test Adapter

L'interface textuelle précédente ne permet pas de repérer rapidement les tests qui posent problème. Google Test Adapter et l'environnement de tests de Visual Studio facilitent la tâche :

  • Menu Test / Fenêtres> / Explorateur de tests : l'explorateur de tests s'ouvre sur la gauche de votre écran.
  • Il "mouline" pendant plusieurs secondes (cf. bande verte tournante dans le haut de l'explorateur de tests, voir Figure 3) pour déterminer la liste de vos tests. NB : cette étape prend du temps, mais n'est à réaliser qu'une seule fois.

    explorateurDeTestsEnTrainDeMouliner image

    Figure 3 : Explorateur de tests en train de mouliner (cf. bande verte tournante)

  • Dans l'explorateur de tests, cliquez sur Exécuter tout. Pendant quelques instants, cet explorateur indique, dans son bandeau haut, que Visual Studio mouline. Puis, il affiche le résultat des tests.
  • Clic gauche sur un test en erreur, agrandissez la fenêtre du bas de l'explorateur de tests pour voir le détail du problème et accéder, en cliquant sur la ligne qui vous intéresse dans la StackTrace en bas à gauche de l'explorateur de tests, à la ligne concernée dans le fichier des tests (cf. Figure 4, notez que, dans l'affichage de testsUnitaires.cpp, le curseur est au niveau de la ligne 14, car on a cliqué sur testsUnitaires.cpp:14 en bas de l'explorateur de tests).

    explorateurDeTestsEnTrainDeMouliner image

    Figure 4 : Affichage des informations d'un test en échec

  • Corrigez votre source (NB : il peut arriver aussi que votre test soit faux, mais c'est beaucoup plus rare !), puis relancez vos tests en cliquant, dans l'explorateur de tests, sur Exécuter tout ou Exécuter… v / Exécuter les tests échoués. Dans notre exemple, modifiez mesFonctionsMathematiques.c de la manière suivante pour obtenir des tests réussis (cf. Figure 5) :
#include "mesFonctionsMathematiques.h"

// Version corrigée

int factorielle(int const n)
{
	int fact = 1;
	for (int i = 2; i <= n; ++i) // Correction : "<=" au lieu de "<"
		fact *= i;
	return fact;
}

bool estUnCarreParfait(int const n)
{
	int i;
	for (i = 0; i*i < n; ++i); // Correction : "i = 0" au lieu de "i = 1"
	return (i*i == n);
}

explorateurDeTestsApresExecutionTout image

Figure 5 : Explorateur de tests quand tous les tests sont OK

4.2 Cas d'une solution Visual Studio contenant déjà un projet console (par exemple, une application SFML)

4.2.1 Principe

Pour traiter ce cas, nous nous ramenons au cas précédent. Pour ce faire, nous décomposons notre solution en un projet console (qui est une coquille presque vide) et un projet librairie statique (qui contient l'ensemble de votre code).

4.2.2 Exemple

Par exemple (SVP, déroulez cet exemple sur votre propre projet), supposons que vous ayez créé un projet SFML appelé JeuDeLaMortQuiTue avec la procédure vue depuis le début de cette U.V. :

  • Ouvrez votre solution JeuDeLaMortQuiTue.
  • Menu Fichier / Nouveau / Projet... : une fenêtre s'ouvre.
  • Choisissez Projet Win32, indiquez MaBibliotheque au niveau du champ Nom :, vérifiez que le champ Solution : (en bas à gauche) a la valeur "Créer une nouvelle édition", et cliquez sur OK.
  • Une fenêtre d'assistant apparaît : cliquez sur Suivant>
  • Cochez la case Projet vide, sélectionnez Bibliothèque statique, décochez En-tête précompilé, et cliquez sur Terminer.
  • Avec l'explorateur de solutions
    • Si jamais, ils sont présents, supprimez (définitivement) les fichiers stdafx.h, targetver.h et stdafx.cpp
    • Clic-droit sur "Fichiers sources, puis Ajouter / Nouvel élément… . Une fenêtre s'ouvre : choisissez Fichier C++, donnez le nom monMain.cpp, et cliquez sur OK. Dans ce fichier source :
      1. recopiez tout le contenu de main.cpp de votre projet JeuDeLaMortQuiTue ;
      2. ajoutez la ligne include "monMain.h"
      3. remplacez int main() par int monMain()
    • Même manipulation en cliquant droit sur Fichiers sources pour créer monMain.h avec le contenu :
#pragma once
int monMain();
  • Votre projet MaBibliotheque a besoin d'accéder aux fichiers d'include de la SFML. Donc, clic droit sur MaBibliotheque, Propriétés.
    • Une fenêtre s'ouvre. Dans la colonne de gauche, sélectionnez C/C++.
    • Dans le champ Autres répertoires Include, mettez C:\Software\SFML-2.4.2\include Cliquez sur OK
  • Modifiez main.cpp du projet JeuDeLaMortQuiTue en remplaçant son contenu par :
#include "../MaBibliotheque/monMain.h"

int main()
{
	return monMain();
}
  • Dans l'explorateur de solutions, pour chaque fichier .h ou .cpp de votre projet JeuDeLaMortQuiTue, excepté le fichier main.cpp, cliquez gauche sur le fichier, puis menu Fichier / Déplacer nomFichier vers > / MaBibliotheque. Ainsi, votre projet JeuDeLaMortQuiTue n'est désormais plus qu'une coquille vide qui contient un main() réduit à sa plus simple expression.
  • Votre projet JeuDeLaMortQuiTue a besoin de référencer la bibliothèque MaBibliotheque pour que l'édition de liens se fasse :
    • Dans l'explorateur de solutions, clic gauche sur projet JeuDeLaMortQuiTue. Puis, menu Projet / Ajouter une référence….
    • Cochez MaBibliotheque. Cliquez sur OK.
  • Générez la solution : menu Générer / Générer la solution
  • Définissez JeuDeLaMortQuiTue comme projet de démarrage : dans l'explorateur de solutions, clic droit sur JeuDeLaMortQuiTue, puis clic gauche sur Définir comme projet de démarrage.
  • Avec Menu Déboguer / Exécuter sans débogage, exécutez votre programme pour vérifier que cette restructuration ne l'empêche pas de fonctionner.

4.2.3 Mise en place et exécution de tests unitaires

Pour mettre en place et exécuter des tests unitaires, il suffit désormais de suivre la procédure décrite dans la section Cas d'une solution Visual Studio contenant un projet Win32 (par exemple, une bibliothèque) en tenant compte des spécificités suivantes :

  • Une fois votre projet UnitTest créé conformément à la procédure, ce projet a besoin d'accéder aux bibliothèques de la SFML pour que l'édition de liens se fasse. Donc :
    • Clic droit sur UnitTest, Propriétés
    • Une fenêtre s'ouvre. Dans la colonne de gauche, sélectionnez Editeur de liens.
    • Dans le champ Répertoires de bibliothèques supplémentaires, mettez C:\Software\SFML-2.4.2\lib
    • Dans la colonne de gauche, cliquez sur le triangle devant Editeur de liens pour déplier l'arborescence. Cliquez sur entrée et ajoutez au début du champ Dépendance suplémentaires la chaîne de caractè_res sfml-audio.lib;sfml-graphics.lib;sfml-network.lib;sfml-system.lib;sfml-window.lib; (sans les guillemets)
    • Cliquez sur OK
  • Pour exécuter vos tests unitaires :
    • Définissez UnitTest comme rojet de démarrage : dans l'explorateur de solutions, clic droit sur UnitTests, puis clic gauche sur Définir comme projet de démarrage
    • Ensuite, menu Déboguer / Exécuter sans débogage OU BIEN exécution des tests à partie de l'explorateur de tests.
  • Pour exécuter votre application :
    • Définissez JeuDeLaMortQuiTue comme projet de démarrage : dans l'explorateur de solutions, clic droit sur JeuDeLaMortQuiTue, puis clic gauche sur Définir comme projet de démarrage.
    • Ensuite, menu Déboguer / Exécuter sans débogage

4.2.4 Remarque finale

Si vous avez besoin de créer un nouveau fichier pour votre application, veillez à désormais le créer dans le projet MaBibliotheque afin que le projet JeuDeLaMortQuiTue reste une coquille vide.

Date: 23 mai 2017

Auteur: Michel SIMATIC

Created: 2024-05-06 Mon 13:45

Validate