1. Introduction sur les
Tests Unitaires
Olivier Hoareau – PHPPRO
Septembre 2012
www.phppro.fr
2. Qui suis-je ?
• Animateur Méthodologies Agiles
• Animateur Equipes Technique
• Expert Certifié PHP 5
• Consultant Indépendant (PHPPRO)
• 12 ans de développement Web/PHP/OSS
• 7 ans de projets Grands Comptes
• 4 ans de Coaching Agile
• Bloggeur / AFUP / Conférencier
3. Définition de « Test »
Ensemble de cas à tester (état de l'objet à tester
avant exécution du test, actions ou données en
entrée, valeurs ou observations attendues, et
état de l'objet après exécution), éventuellement
accompagné d'une procédure d'exécution
(séquence d'actions à exécuter). Il est lié à un
objectif
Source : IEEE
4. « Niveaux* » de Tests
Unitaires Intégration
(T.U) (T.I)
Performance
(T.P) Fonctionnel Graphiques
s (T.F) (T.G)
Ergonomie …
(T.E) Sécurité
(T.S)
* cf. Comité Français du Test Logiciel (CFTL : www.cftl.net )
5. Définition de « Test unitaire »
Procédé permettant de s'assurer du
fonctionnement correct d'une partie
déterminée d'un logiciel ou d'une portion d'un
programme (appelée « unité » ou « module »)
Source : Wikipedia
6. Qu’est-ce qu’un test unitaire ?
Paramètres
LOGIQUE ENV / SYS
T.U
Ce qui
Ce qui est testé interagie
Ce qui
teste
Retours
Exceptions
Vérifie Agit Interagit
7. Un test unitaire …
• … n’est pas un test de bout en bout
• … ne doit exécuter que l’ « unité » à tester
• … doit être déterministe
• … ne doit pas dépendre de l’environnement
• … ne doit pas être exhaustif
• … doit utiliser la technologie de l’ « unité »
• … ne teste pas des enchainements de page
• …
8. Idées reçues et Mauvaises pratiques
• Je dois mettre des données en base pour exécuter mon test unitaire
• Je dois paramétrer mon environnement pour faire fonctionner tel ou
tel test unitaire
• Certains tests unitaires ne fonctionnent pas partout
• Certains tests unitaires sont en échec de temps en temps
• Mes tests unitaires ne marchent que sous Windows/Linux/Mac
• Mon test unitaire est long car il fait des appels webservices
• Je dois initialiser le contexte/bootstrap avant de pouvoir tester
unitaire telle ou telle méthode
• Un seul test unitaire par méthode est suffisant
• Les tests unitaires ne servent qu’à tester les cas attendus
• Les tests unitaires ne servent qu’à tester les erreurs possibles
10. Maîtriser les « entrées/sorties »
pour mieux tester
OPTIONNEL
ENTREES
Environnement
Données statiques
TEST UNITAIRE
(« en dur »)
Unité à tester
Résultats statique
(déterministe) Simulateur
SORTIES Bouchon simulateur
d’environnement
11. Simuler grâce au bouchon (1/2)
• Un bouchon permet :
– de renvoyer un résultat attendu (ex: 3)
– de renvoyer un résultat inattendu (ex: 2 au lieu de 3)
– De simuler une erreur inattendue (ex: Exception)
– De ne renvoyer aucun résultat
– de simuler le fait que l’écosystème a été appelé
– …
Grâce au bouchon, vous pourrez tester tous les cas de figures !
12. Simuler grâce au bouchon (2/2)
• Exemple d’opérations « bouchonnables » (= mocks)
– L’envoie d’un email
– L’écriture ou la lecture en base de données
– L’écriture ou la lecture sur le système de fichiers
– L’appel d’un ou plusieurs webservices
– L’accès à la mémoire partagée
– L’exécution d’un calcul mathématique
– L’appel d’une API tierce
– …
Grâce au bouchon, vous pourrez tout simuler !
13. Niveau de bouchonnage
ou la vraie différence en les T.U et les T.I
T.U T.I
Bouchonnage = 100%
i.e. 100% des appels de méthodes
externes à la méthode/classe à
≠ 0 <= Bouchonnage < 100%
i.e. on bouchonne sélectivement
les composants / méthodes qui ne
tester sont bouchonnés sont pas intéressants pour le test
Tester le fonctionnement Tester l’interconnexion
d’un seul composant précis de plusieurs composants
14. Test 1. Instanciation et Paramétrage du Bouchon Bouchon
unitaire (env)
2. Instanciation unité
Unité testée
3. Injection du Bouchon (ex: Méthode)
4. Exécution méthode
5. Pré-traitement
6. Action environnement
7. Trace
8. Réponse paramétrée
9. Post-traitement
10. Réponse attendue
11*. Assertion(s) sur réponse (* = déplacé entre 3 et 4 en cas d’exception)
12. Vérifications des opérations enregistrées sur l’environnement (bouchon)
15.
16. Les frameworks de Mock (bouchons)
• Personnalisé / sur mesure à développer
• Open source PHP
– getMock() de PHPUnit
http://www.phpunit.de/manual/3.5/en/test-doubles.html#test-doubles.mock-
objects
– mock() / getMockController() de Atoum
https://github.com/mageekguy/atoum/wiki/Utiliser-les-bouchons
– Mock::generate() de SimpleTest
http://www.simpletest.org/en/mock_objects_documentation.html
–…
Utilisez le framework de mock adapté à vos besoins et en fonction de votre outil de test
17. Quels cas tester ?
• Au moins 3 catégories de cas à tester :
– Les Cas nominaux / en succès
• vérifier que la méthode fait le job en
fonctionnement normal
– Les Cas d’erreurs
• vérifier que la méthode gère bien les erreurs
– Les Cas aux limites / tordus / peu communs
• vérifier que la méthode est robuste
Attention 1 catégorie = 1 à plusieurs cas de tests (i.e. tests)
18. Comment nommer les cas de tests ?
test[NomMethode][Cas][Resultat/ComportementAttendu]()
Préfixe souvent
Titre du cas spécifique
imposé par les
à tester, ou de l’état de
outils de tests
départ
Résultat ou comportement attendu
Nom de la méthode de la méthode testé, ou effet attendu
testée (i.e. à exécuter) sur l’environnement
Exemples
testUpdateProviderCatalogForSuccessUpdateHasModifiedDb()
testUpdateProviderCatalogForUnexpectedProviderErrorThrowException()
19. Les états possibles d’un test
• . Success : en succès
• E Error : Erreur inattendue à l’exécution
• F Failure : au moins une assertion est fausse
• I Incomplete : aucune assertion dans ce test
• S Skipped : test ignoré
Etapes recommandées (dans l’ordre) :
EF.
20. TDD : Test Driven Development
• Aussi appellé « Test-Before »
• C’est l’art :
– d’écrire le test avant le code
– de ne pas modifier le code si il n’existe pas un test en
error/failure
– de rajouter un test en echec pour tout bug à fixer
– de ne pas développer bille en tête
– d’améliorer son code en continue
– De ne pas avoir que son collègue qui est le seul à
daîtriser telle ou telle partie de code parte en
vacances ;)
21. Refactoring
où l’étape qu’on oublie souvent…
• Vous avez écrit un test en échec
• Vous avez écrit ensuite le code applicatif
• Votre test est maintenant en succès
• Vous pensez avoir terminer votre test et pouvoir écrire un
nouveau test
• Vous vous trompez ! EF.R
• C’est le moment de refactorer (i.e. améliorer / réécrire le
zone de code applicatif que vous venez de tester avec votre
nouveau test
• C’est en effet plus sécurisant de modifier du code lorsque
tous les tests sont au vert ! (i.e. en succès)
22. Pourquoi écrire des tests unitaires ?
• Pour ne plus avoir peur de modifier le code
• Pour garantir la non régression sur des
comportements clés
• Pour avoir une étape de contrôle supplémentaire
dans l’automatisation du packaging / déploiement
• Pour être capable de relire le code d’une
fonctionnalité que l’on a pas écrit
• Pour être capable de mettre du code à la poubelle
sans avoir peur de perdre quelque chose
• …
23. Intégration Continue et T.U
• Exécuter les T.U sur chaque commit / push sur le
dépôt
• Exécuter les T.U sur un serveur neutre / central et
non sur un poste de développement
• Historiser les rapports de T.U pour suivre la
qualité dans le temps
• Automatiser le packaging / déploiement suite à
l’exécution en succès des T.U
• Exécuter les T.U sur la prochaine version (beta) de
PHP pour anticiper la migration
• …
Utiliser un serveur d’intégration continue tel que Jenkins (ex: Hudson)