Copy of https://perso.isima.fr/loic/cpp/catch.php
tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
Institut d'informatique ISIMA
  • twitter
  • linkedin
  • viadeo

[++C] Catch2

 Cette page commence à dater. Son contenu n'est peut-être plus à jour. Contactez-moi si c'est le cas!

Date de première publication : 2017/09/11

La bibliothèque de tests Catch2 est une bibliothèque de tests unitaires pour le C++.

A ce jour, trois versions "co-existent" : une version 1 pour supporter le vieux CPP d'avant 2011, la version 2 dans un seul fichier d'entête pour les codes post 2011, et une v3 qui n'est plus avec un seul fichier d'entête (mais qui serait plus rapide et plus sûre)

Nous allons nous contenter de la version 2 car son utilisation est hyper simple : il suffit d'inclure le fichier d'entête catch.hpp et de définir une petite macro pour créer un main() capable de lancer tous les tests.

Pour avoir la dernière version disponible de Catch2, il suffit de faire :


wget https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp

Généralités

On va écrire du code de test, c'est-à-dire une ou plusieurs fonctions qui vérifient que du code que l'on a écrit a un comportement défini au préalable.

Les fonctions de tests peuvent être des succès, des échecs (bloquants ou non) et lever des exceptions.

On va utiliser principalement les macros CHECK et REQUIRE

Il existe également les formes CHECK_FALSE et REQUIRE_FALSE

Si vous avez besoin de comparer des nombres rééls, vous avez besoin d'un test avec une certaine tolérance. C'est obtenu avec Approx

REQUIRE( valeur_a_verifier == Approx( 10.2 ) );

Par défaut, si une exception est levée lors d'une condition, la condition sera supposée fausse. Il est toutefois possible d'affiner le comportement des tests vis à vis des exceptions avec les macros :

REQUIRE_THROWS_AS( m.create(), std::bad_alloc );

Code principal pour le lancements des tests

Pour exécuter les tests, il suffit de définir CATCH_CONFIG_MAIN dans un fichier de code cpp

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

Exemples

Il existe plusieurs manières de rédiger des tests avec la bibliothèque. Je vais me contenter de vous en montrer une avec les macros TEST_CASE et SECTION

Pour faire simple, TEST_CASE sera l'environnement de test et cet environnement sera réinitialisé pour chaque SECTION. Vous pouvez mettre autant de SECTIONs que vous le voulez dans un TEST_CASE et écrire autant de TEST_CASEs que vous le voulez

Chaque TEST_CASE devra avoir un nom unique et pourra être paramétré par un système de tags

Voici maintenant un exemple de fichier de tests :

TEST_CASE ("Vecteur1") {
  const Vecteur v;
 
  REQUIRE ( v.capacity() >= 10 );
  REQUIRE ( v.size()     == 0  );
}


TEST_CASE ("Vecteur2" ) {
  Vecteur v(20);
 
  REQUIRE ( v.capacity() == 20 );
  REQUIRE ( v.size()     == 0  );
}

Dans l'exemple suivant, "Vecteur3" sera une batterie de tests (SECTION) qui s'appuient tous sur le même environnement de départ (fixture)

TEST_CASE ("Vecteur3" ) {
  Vecteur v(5);
 
  SECTION("ajout de quelques elements") {
    REQUIRE ( v.capacity() == 5 );

    for (int i=0; i<4; ++i)
      v.push_back(i*1.0);

    REQUIRE ( v.size()     == 4  );
  }

  SECTION("tableau un peu agrandi") {
    // on peut verifier que vecteur est bien un nouveau :-) 
  REQUIRE ( v.capacity() == 5 );
    for (int i=0; i<6; ++i)
      v.push_back(i*1.0);

    REQUIRE ( v.capacity()  == 10 );
    REQUIRE ( v.size()      == 6  );
  }

  SECTION("on verifie les valeurs dans le vecteur") {
    for (int i=0; i<25; ++i)
      v.push_back(i*1.0);

    REQUIRE( v.capacity() ==  40 );
    REQUIRE( v.size()     ==  25 );

    for (int i=0; i<25; ++i)
      CHECK(v[i] == Approx(i*1.0+0.1));  // :-)
  }

  SECTION("on verifie les exceptions") {
    REQUIRE_THROWS_AS( v[-1] == 0, Vecteur::OutOfRangeException); 
    REQUIRE_THROWS_AS( v [6] == 0, std::bad_alloc);  // :-)
   }
}

Bien entendu, les tests commentés avec des smileys ne sont pas validés

Voici une copie écran possible de ce que l'on peut obtenir :

Pour finir, je voudrais juste ajouter que l'on peut choisir les tests à exécuter avec les tags et choisir le format de sortie, entre autres ...