Property-based testing

Property-based testing

PBT, pour les intimes.

J'étais familier du concept depuis un moment déjà, mais je n'avais pas réussi à l'intégrer à ma pratique quotidienne du développement ; cela a enfin changé.

Mais déjà, qu'est-ce que le PBT ? Considérons quelques exemples :

  • Une fonction random({ min, max }) renvoyant un nombre au hasard entre 2 bornes. Une approche de test classique nous obligerait à injecter une fonction génératrice de hasard (injection de dépendance). Dans une approche de PBT, nous allons plutôt vérifier qu'étant donnés 2 nombres min et max tels que min < max, la propriété min ≤ random({ min, max }) ≤ max est toujours vérifiée.

  • Une fonction affine f(x) = 1 + x/2. Classiquement, nous choisirions 2 abscisses pour vérifier que la fonction calcule les bonnes ordonnées. Par exemple (0,1) et (2,2). Pour autant, il existe une infinité de fonctions passant par ces points, à commencer par une jolie parabole. Ces tests constituent donc une condition nécessaire (si la fonction ne passe pas par l'un de ces points, alors ce n'est pas la droite y = 1 + x/2) mais non suffisante. Le PBT ne prouve rien non plus, mais il permet de vérifier que quel que soit le couple d'abscisses x1 et x2 (x1≠x2), la pente du segment [(x1,f(x1)), (x2,f(x2)] est égale à 1/2… en tout cas la chose est réputée vraie tant que l'on n'a pas trouvé de contre-exemple.

  • Une collection de photographies et 3 actions : supprimer, annuler la suppression, restaurer une image. Je vous épargne le test "classique" : pour tel état et telle action, j'attends tel résultat. Ici, nous pourrions vérifier que quelles que soient les actions menées, peu importent leur nombre et leur nature, le nombre total d'images (collection + corbeille) est préservé.

Moi, je dis* : chouette.

Tout cela est donc radicalement différent de ce à quoi nous sommes habitués. On n'attend pas un résultat — impossible, puisque les paramètres sont tirés au hasard, mais on vérifie des propriétés, des invariants du métier. Qui a dit #DDD ?! C'est très beau.

Soyons clairs : ça ne prouve rien de plus qu'un test classique. Même si nous effectuons 10 tests, que le framework de test tire 1000 valeurs au hasard à chaque test et que la propriété est vérifiée les 10000 fois, il n'est pas exclu de tomber sur un contre-exemple la 10001ème fois. Mais les probabilités jouent quand-même en notre faveur. On fait du dev, pas des maths 🙏

Voilà. Maintenant, comment faire de cet outil une aide au quotidien ?

Personnellement, 2 choses me bloquaient :

  • Vouloir absolument faire du PBT et du Test-driven development (TDD) 😳 Les 2 notions étant orthogonales, cela n'est pas exclu. Cependant, faire du PBT seul (en test-after) est plus simple et déjà fort bénéfique ;

  • Vouloir faire du PBT uniquement 😳, à l'exclusion des autres approches de test. Parce qu'implicitement le PBT serait mieux. Naturellement, l'usage montre que les différentes approches sont complémentaires.

Bref, mettre un peu de nuance pour avancer. On en revient à nos considérations habituelles du TDD : avant d'être un filet de sécurité anti-régression, avant d'être une documentation vivante, les tests sont une aide à l'écriture de code.

A nous de trouver l'usage du PBT qui nous aide.

(*) Je dois 1€ à une personne qui se reconnaîtra

Subscribe to Mathieu Eveillard

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe