Tests basés sur les propriétés en Swift : quand les tests ordinaires échouent
Avez-vous déjà écrit un test unitaire qui réussit parfaitement, puis l'application plante avec des données réelles ? Ça vous dit quelque chose, n'est-ce pas ? Les tests classiques basés sur des exemples (où l'on vérifie une entrée et une sortie spécifiques) sont utiles, mais ils ont un défaut fondamental : ils ne testent que ce que nous avons nous-mêmes imaginé. Et si le bug se trouve à la limite des valeurs acceptables, ou dans une combinaison qui ne nous est tout simplement pas venue à l'esprit ?
C'est là qu'interviennent les tests basés sur les propriétés en Swift. C'est une approche où vous décrivez non pas des cas spécifiques, mais des propriétés qui doivent être vraies pour toutes les données d'entrée. Un framework spécialisé (par exemple, SwiftCheck) génère des centaines de valeurs aléatoires et vérifie si votre propriété n'est pas violée. Si un bug est trouvé, le framework « minimise » les données d'entrée — et vous obtenez l'exemple le plus simple sur lequel tout se casse.
Dans cet article, nous verrons comment intégrer les tests basés sur les propriétés Swift dans votre projet, nous écrirons des exemples de code concrets et nous examinerons quels bugs peuvent être détectés avec cette approche. C'est parti !
Qu'est-ce que le test basé sur les propriétés et pourquoi en a-t-on besoin ?
Imaginez que vous testez une fonction qui trie un tableau. Au lieu d'écrire 10 tests avec différents tableaux, vous dites : « pour tout tableau, après le tri, la longueur ne change pas et chaque élément est inférieur ou égal au suivant ». C'est ce qu'on appelle une propriété — un invariant qui doit toujours être respecté.
Les tests basés sur les propriétés en Swift sont parfaits pour :
- Vérifier les fonctions mathématiques (addition, division, arrondi) ;
- Tester les analyseurs et les sérialiseurs (la sérialisation → désérialisation doit retourner l'original) ;
- Vérifier la logique métier avec un grand nombre de combinaisons ;
- Rechercher des régressions sur les valeurs limites.
Le principal avantage : vous trouvez des bugs dont vous ignoriez même l'existence. Et c'est, vous en conviendrez, plus intéressant que de confirmer l'évidence.
SwiftCheck — l'outil principal pour les tests basés sur les propriétés en Swift
Dans le monde Swift, le framework le plus populaire pour cette approche est SwiftCheck. Il porte les idées de Haskell (bibliothèque QuickCheck) et s'intègre parfaitement avec XCTest.
Pour commencer, ajoutez la dépendance dans votre Package.swift :
// swift-tools-version:5.9import PackageDescription
let package = Package( name: "MyProject", dependencies: [ .package(url: "https://github.com/typelift/SwiftCheck.git", from: "0.12.0") ], targets: [ .testTarget( name: "MyProjectTests", dependencies: ["SwiftCheck"]), ])Maintenant, vous pouvez écrire des tests. Examinons la syntaxe de base.
Premier test basé sur les propriétés : vérification de l'addition
Écrivons une propriété simple : « l'addition est associative ». Pour tous les entiers, a + b + c doit être égal à (a + b) + c.
import XCTestimport SwiftCheck
class MathPropertiesTests: XCTestCase { func testAdditionIsAssociative() { property("L'addition est associative") <- forAll { (a: Int, b: Int, c: Int) in return (a + b) + c == a + (b + c) } }}Lancez le test — il exécute 100 combinaisons aléatoires (par défaut). Si au moins une échoue, SwiftCheck affichera les valeurs spécifiques. Notez que nous ne spécifions aucun nombre concret ! Les tests basés sur les propriétés Swift génèrent les données eux-mêmes.
Vérification de la transformation inverse (roundtrip)
C'est le modèle le plus courant. Supposons que nous ayons une structure qui se sérialise en JSON. Propriété : « après sérialisation et désérialisation, nous obtenons le même ob