AS3 : Tests unitaires Asynchrones
Contexte
Hormis l'ajout API'S, le langage AS3 n'a pas beaucoup évolué depuis FP9.
je crois que j'ai eu assez le loisir de le triturer dans tout les sens, de faire et refaire un certain nombre d'erreurs.
J'ai notamment eu l'occasion :
- d'user des design patterns (en particulier les pricipaux GOF) jusqu'au non sens.
- de programmer à la mode événementielle et sur-dynamiquement jusqu'à l'indébuggabilité voir l'étouffement du programme
- de me retrouver avec des memory leaks de trois mètre de long
- de réécrire des centaines de fois (des milliers ?), la même chose façon anti-DRY
- de faire de progs nécessitant des configs absolument phénoménales pour afficher 3 images
(CoC) - de coder complètement au feeling ne sachant pas ce que j'allais réaliser : la prog. en écriture automatique.
Ce genre d'erreur influence la manière que l'on a de programmer.
Parfois je tente de fixer le style courrant avec un petit framework utile pour un certain type de projet.
De temps en temps, en fonction du vent, de la mode et de ce que font les autres, ce framework reste, évolue, grossi, se dégraisse, ou disparait.
Après quelques essais je pense que les tests unitaires sont vraiment un très bon outils pour optimiser ce processus.
Je les ai longtemps laissés de coté pour ne pas m'encombrer de lignes de code "inutiles".
Après essais, je sais que ce n'est pas pour tout de suite en mode "production".
Cela change cependant réellement l'approche de la prog et m'est quand même utile dès a présent.
Première expérience pratique avec les tests unitaires
Coder les tests avant le programme lui même, logique non ?
- C'est vraiment quelque chose de positif.
- Cela force a réfléchir à ce que le programme doit faire avant de l'écrire.
- J'ai quand même tendance à écrire au-moins un premier jet d' interface, ensuite j'écris la classe de test en essayant de viser les erreurs types qui peuvent être rencontrées (par exemple pour un "stepper" allant de 0 à n, se retrouver avec un compteur > n ou < 0; modifier la valeur de n et re-tester... )
Les tests dirigent le développement
C'est une phase créative qui donnes des idées :
- Si je vois que ça ne colle pas avec la logique d'utilisation que l'écriture des tests fait ressortir, je modifie l'interface
- Je lance les tests et je m'assure que tout plante comme prévu (sauf peut-être l'instanciation).
- je prog. l'implémentation de la classe testée jusqu'à ce que l'ensemble des test soient "OK".
- Le nombre d'erreurs se réduit progressivement.
- Pendant ce temps il arrive que je m'aperçoive que je n'ai pas prévu un type d'erreur :
Ce n'est pas grave il faut coder un test permettant de le mettre en évidence et corriger le problème.
Meilleur qualité du code ?
Je ne dirais pas que faire des tests entraine forcément la création d'un code de bonne qualité :
- Les tests unitaires ne garantissent pas la performance, ou la lisibilité du code.
- il peuvent attirer l'oeil sur des problèmes de conception.
- On peut obtenir une classe absolument robuste (dans le cas ou les utilisations sont élaborés finement et les erreurs possibles prévues)
Evolution
Une classe est soumise à différents types d'évolutions, en particulier :
- la réutilisation dans un contexte a priori inattendu,
- l'ajout de fonctionnalité(s)
- la factorisation.
- Dans le premier cas avec les tests, on se sent vite à l'aise : ça va marcher c'est sur.
Si une erreur apparaît, on réécris un test et corrige le problème lié au contexte qui si il réapparait sera immédiatement mis en évidence par les tests. - Dans les autres cas, les tests sont la pour alerter si quelque chose se décale au fur et à mesure de l'évolution de ce bloque de programme.
Attention :
- Je le répète : les tests unitaires ne garantissent pas la performance, ou la lisibilité du code.
- Ils sont eux-même susceptibles de contenir des erreurs.
- Il appartient au développeur de distinguer TOUS les comportements attendus et inattendus
- Le développement dirigé par les tests fait exploser le nombre de lignes à écrire : cela doit s'inscrire sur le long terme pour que ce soit intéressant, et il est parfois difficile de le savoir à l'avance.
Tests synchrones et asynchrones avec ASUNIT
- J'ai choisi d'utiliser ASUNIT, qui fonctionne dans des contextes variés.
Le fonctionnement est assez simple il faut associer les sources (répetoire as3/src) au projet contenant les classes à tester.
En mode synchrone j'ai suivi cet exemple
En mode asynchrone on peut continuer d'étendre asunit.framework.TestCase
Lors du test et avant chaque appel à une méthode asynchrone il suffit de référencer le retour de la méthode addAsync() quelque part (c'est un fonction) : Le déroulement du test est bloqué tant que cette fonction n'est pas exécutée. On peut ainsi utiliser plusieurs fois addAsync() pour tester un cas d'utilisation complet nécessitant plusieurs appels asynchrones (ex : une pile de chargement )
- Des exemples de tests : asunit-test.zip
L'archive contient une classe Stepper et le corps de base d'une pile de chargement (LoadingQueue) façon "interface" (ie : pas d'événementiel ni de callback hormis les événements natifs) codées avec cette méthode. j'ai notamment ajouté après coup l'aspect cyclique optionnel du Stepper. A ce moment c'est très sympa d'avoir de quoi tester. les "TestCase"'s la "TestSuite" et la classe principale de lancement des tests sont inclus.
Ce qui a été intéressant ici pour moi ce n'est pas les classes mais la démarche pour les créer.
Maintenant il me faut apprendre à écrire mieux les tests...
0 Commentaires
-
(you)Feb 23, 2012 at 00:07