Tests basés sur les propriétés en Kotlin : casser le code plus vite que tu ne le penses

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

Pourquoi les tests classiques mentent et tu les crois



Imagine : tu as écrit une fonction, tu l'as couverte de trois tests unitaires. Cocher vert. CI passe. Production — bug. Ça te dit quelque chose ?



Le problème des tests unitaires classiques, c'est qu'ils vérifient des exemples spécifiques. Tu inventes toi-même les données d'entrée et tu écris toi-même le résultat attendu. C'est comme un examen où l'étudiant compose lui-même les sujets. Tôt ou tard, tu vas rater un cas limite — null, une liste vide, un nombre négatif ou une chaîne avec des caractères Unicode.



C'est là qu'intervient le test basé sur les propriétés (ou property-based testing). Au lieu d'écrire : « si on passe 5, on doit obtenir 25 », tu formules une propriété : « pour tout nombre entier, le carré est toujours non négatif ». Et le framework génère lui-même des centaines de valeurs aléatoires et vérifie cette propriété.



Dans cet article, nous allons voir comment utiliser le test basé sur les propriétés en Kotlin avec la bibliothèque Kotest. Tu apprendras à écrire des tests fiables, à trouver des bugs dès les premières étapes et à ne plus avoir peur du refactoring. Ce n'est pas juste de la théorie ennuyeuse — nous allons écrire du code réel que tu pourras appliquer immédiatement dans un projet.



Qu'est-ce que le property-based testing et pourquoi Kotlin ?



L'idée n'est pas nouvelle — elle a été popularisée par la bibliothèque QuickCheck pour Haskell dès 1999. Mais ce n'est que maintenant, avec la complexité croissante des systèmes backend et des microservices, que le test basé sur les propriétés devient un must-have dans la stack du développeur.



Kotlin est le langage idéal pour cette approche. Pourquoi ?



  • Capacités fonctionnelles : lambdas, fonctions d'extension, immutabilité — tout cela simplifie l'écriture de propriétés pures.
  • Kotest — un framework puissant qui supporte nativement les tests basés sur les propriétés, les générateurs et le Shrinking (algorithme de minimisation de l'exemple défaillant).
  • Compatibilité avec Java : tu peux tester du code legacy écrit en Java en utilisant les mêmes approches.


Allons droit au but. Voici un exemple qui va bouleverser ta vision des tests.



Premier test basé sur les propriétés en 5 minutes



Supposons que nous ayons une fonction qui vérifie si une chaîne est un palindrome :



fun isPalindrome(s: String): Boolean {    val cleaned = s.filter { it.isLetterOrDigit() }.lowercase()    return cleaned == cleaned.reversed()}


Un test classique ressemble à ceci :



@Testfun `test known palindromes`() {    assertTrue(isPalindrome("A man, a plan, a canal: Panama"))    assertTrue(isPalindrome("racecar"))    assertFalse(isPalindrome("hello"))}


Tout fonctionne. Mais que se passe-t-il si les données d'entrée contiennent des espaces, des chiffres ou des symboles ? Et si la chaîne est vide ? Et si elle est composée uniquement d'espaces ?



Écrivons maintenant un test basé sur les propriétés avec Kotest :



import io.kotest.core.spec.style.StringSpecimport io.kotest.property.forAllimport io.kotest.property.arbitrary.string

class PalindromePropertyTest : StringSpec({ "Toute chaîne nettoyée doit être un palindrome d'elle-même" { forAll<String> { original -> val cleaned = original.filter { it.isLetterOrDigit() }.lowercase() isPalindrome(cleaned) == true } }})


Que se passe-t-il ici ? forAll<String> génère des chaînes aléatoires : vides, avec des espaces, avec de l'Unicode, avec des chiffres. Et pour chacune, il vérifie la propriété. Si une seule chaîne viole l'affirmation — le test échoue, et Kotest affiche l'exemple reproductible minimal.



Déjà à ce stade, tu peux trouver des bugs. Par exemple, si la chaîne est composée uniquement d'espaces — filter renverra une chaîne vide, et isPalindrome("") renverra true. Un test classique aurait laissé passer cela.



Générateurs : ton

Blogs

Book Recommendations