Tests basés sur les propriétés en C++ : attrapez les bugs que vous ne cherchiez pas

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Et si vos tests unitaires mentaient ?

\n

Vous avez écrit une centaine de tests unitaires. Ils passent. Le code en C++ a l'air parfait. Mais lorsque vous lancez l'application en production, elle plante avec une erreur de segmentation à la 100500e requête. Une douleur familière ?

\n

Les tests unitaires traditionnels ne vérifient que ce que vous avez vous-même imaginé. Ils sont aveugles aux scénarios qui ne vous sont pas venus à l'esprit. Les tests basés sur les propriétés (ou property-based testing, PBT) résolvent ce problème radicalement : ils ne vérifient pas des exemples spécifiques, mais prouvent des propriétés (properties) de votre code pour des millions de données d'entrée aléatoires.

\n

Dans cet article, nous verrons comment implémenter les tests basés sur les propriétés en C++ avec la bibliothèque RapidCheck, et nous constaterons comment ils attrapent des bugs que les tests unitaires ordinaires laissent passer. Prêts à faire vraiment souffrir votre code ? C'est parti.

\n\n

Tests basés sur les propriétés : la philosophie en 30 secondes

\n

Imaginez que vous testez une fonction de tri. Test classique : sort([3,1,2]) == [1,2,3]. Ok, on a vérifié un cas.

\n

Approche basée sur les propriétés : « Pour toute liste d'entiers, après le tri, la longueur ne change pas, les éléments sont classés par ordre croissant, et chaque élément de la liste d'origine est présent dans la liste triée ». Le framework génère des centaines de listes aléatoires (y compris vides, avec des doublons, avec des nombres négatifs) et vérifie ces propriétés.

\n

L'idée clé : vous décrivez des invariants (properties) qui doivent toujours être vrais, et non des entrées et sorties spécifiques.

\n\n

Quand le PBT est-il particulièrement utile en C++ ?

\n
    \n
  • Algorithmes et structures de données (tris, recherche, graphes)
  • \n
  • Analyseurs syntaxiques et sérialiseurs (encodage/décodage)
  • \n
  • Fonctions mathématiques (opérations inverses, plages de valeurs)
  • \n
  • Gestion de la mémoire (fuites, double libération)
  • \n
  • Tout code où il existe des invariants clairs
  • \n
\n\n

RapidCheck : votre nouveau meilleur ami

\n

En C++, il existe plusieurs bibliothèques pour le PBT, mais RapidCheck est la plus mature et la plus pratique. Elle s'inspire de la bibliothèque Haskell QuickCheck et s'intègre parfaitement avec Google Test et Catch2.

\n

L'installation est simple : c'est une bibliothèque header-only, il suffit de copier les fichiers de include/rapidcheck dans votre projet. Ou utilisez Conan/vcpkg.

\n\n

Premier test : propriété d'opération inverse

\n

Supposons que nous ayons une fonction qui encode une chaîne en base64 et la décode. Quelle propriété est évidente ? « Le décodage après l'encodage renvoie la chaîne d'origine ».

\n
#include <rapidcheck.h>\n#include <string>\n\nstd::string encode_base64(const std::string& input);\nstd::string decode_base64(const std::string& input);\n\nint main() {\n    rc::check("Le décodage après l'encodage renvoie l'original",\n              [](const std::string& original) {\n                  // Le générateur de chaîne est déjà intégré\n                  auto encoded = encode_base64(original);\n                  auto decoded = decode_base64(encoded);\n                  RC_ASSERT(decoded == original);\n              });\n    return 0;\n}\n
\n

Que se passe-t-il ici ? RapidCheck génère des chaînes aléatoires (y compris vides, avec Unicode, avec des octets nuls). Pour chacune, il vérifie la propriété. S'il trouve un contre-exemple — minimal (shrinking), qui casse toujours le test. C'est de l'or : vous n'obtenez pas simplement « il y a un bug », mais un cas reproductible concret.

\n\n

Propriétés avancées : plus que l'égalité

\n

Monotonie et idempotence

\n

Pour la fonction remove_duplicates :

\n
    \n
  • Idempotence : si on l'applique deux fois, le résultat ne change pas.
  • \n
  • L'ordre n'a pas d'importance : la liste résultante contient les mêmes éléments que la liste d'origine, mais sans doublons.
  • \n
\n
#include <vector>\n#include <algo                

Blogs

Book Recommendations