Trop souvent tester son code se fait soit en fin de projet, soit pas du tout ; et correspond à une contrainte pour les développeurs. C’est pourtant à la fois un confort et une assurance dans la qualité et de son travail. A travers cette présentation, “tester c’est douter”, j’ai voulu provoquer l’envie de s’y mettre. Expliquer comment les tests amènent à remettre correctement son travail en cause.
Pour ce faire j’ai choisi une approche agnostique, n’évoquant ni les technos ni la manière de les utiliser.
J’ai privilégié de présenter plutôt la logique des tests :
Expliquer ce qu’est un test, les différents types et quand les utiliser.
Evoquer le pattern des tests doubles et différencier un mock d’un stub. Présenter une série de bonnes pratiques pour coder correctement ses tests et éviter les tests smells
Présentation d’un cas pratique pour appuyer la théorie
Présentation des patterns TDD et BDD pour introduire les tests au coeur de ces développements.
4. LinkValue
#TheGreatPlaceToGeek
Test automatisé
● C’est un code qui vérifie la validité d’un autre
● C’est un code qui surveille les régressions
● C’est un code dont l'exécution ne nécessite pas l'intervention
d'un humain
6. LinkValue
#TheGreatPlaceToGeek
Pourquoi écrire des tests ?
Plus-value à moyen terme:
● VSR et VABF plus court
● Facilite l’implémentation de nouvelles fonctionnalités
● Limite voir supprime les régressions
● Facilite la migration et la refactorisation
7. LinkValue
#TheGreatPlaceToGeek
Pourquoi écrire des tests ?
Plus-value à long terme:
● Limite la dette technique
● Accélère la vitesse de développement
● Surveille/ évite le retour des bugs corrigés
● Coût des bugs amoindri
10. LinkValue
#TheGreatPlaceToGeek
Le test unitaire
● Teste unitairement une portion de code
● Assure le bon fonctionnement d’une méthode
● Mock de toutes les dépendances
● Test à granularité fine
● Test de type white box
11. LinkValue
#TheGreatPlaceToGeek
Le test d’intégration
● Teste l’assemblage de plusieurs composants logiciels indépendants
● Ne vérifie pas la conformité des composants
● Assure la cohésion d’un système
● Test à granularité moyenne
● Test de type white box
12. LinkValue
#TheGreatPlaceToGeek
Le test fonctionnel
● Simule l’action d’un utilisateur
● Ne tient pas compte des différentes couches applicatives
● Vérifie le résultat général
● Test à grosse granularité
● Test de type black box
16. LinkValue
#TheGreatPlaceToGeek
Définition d’un Stub
● Un Stub est centré sur le SUT
● Il lui fournit une indépendance
● Il lui fournit des données utilisées
pendant les tests
● Il ne fait jamais échouer le test
● “State-based testing”
17. LinkValue
#TheGreatPlaceToGeek
Définition d’un Stub
● Un Stub est centré sur le SUT
● Il lui fournit une indépendance
● Il lui fournit des données utilisées
pendant les tests
● Il ne fait jamais échouer le test
● “State-based testing”
18. LinkValue
#TheGreatPlaceToGeek
Définition d’un Mock
● Un Mock est centré sur le test
● Il décide si le test échoue ou réussit
● Une assertion se fait contre le Mock
● On ne teste pas le résultat mais la
manière de l’obtenir
● “Interaction testing”
20. LinkValue
#TheGreatPlaceToGeek
Les autres tests doubles
● Dummy : passer en paramètre à l’objet mais n’est jamais appelé
● Fake : l’objet possède une implémentation simple qui retourne toujours
le même résultat
● Spy : objet qui surveille le comportement d’un code ne pouvant être
relevé
21. LinkValue
#TheGreatPlaceToGeek
On s’en mock
● Dummy, spies, fake sont des cas spécifiques de mocks ou de stubs
● Comprendre et maitriser l’utilisation des mocks et des stubs induit
l’utilisation des autres sans en avoir pleinement conscience
● De toute facon, par abus de language, on appelle tout un “mock”
23. LinkValue
#TheGreatPlaceToGeek
Avant-propos :Tests smells
Test smells définit tout type de test qui ne valide pas la qualité du code
et/ou gène le travail du développeur.
● Test difficile à comprendre et à maintenir.
● Test trop long.
● Test un faux positif ou faux négatif.
● Test avec effet de bord.
● Test multiple comportement en une fois.
24. LinkValue
#TheGreatPlaceToGeek
● Mock toutes les dépendances
● Seule la classe testée doit être instanciée
● Tester une classe, une méthode et un comportement à la fois
● Si plusieurs comportements par méthode, faire un test pour chacun
Un test unitaire doit être unitaire
25. LinkValue
#TheGreatPlaceToGeek
Un test unitaire doit être rapide
● Il teste la vitesse d’éxécution du script
● Ne dialogue avec personne (bdd, classe tiers, webservice …)
● Confort pour le développeur (lancer tous les tests avant chaque
commit)
27. LinkValue
#TheGreatPlaceToGeek
CODEZ PROPRE !!!
● Les tests sont le reflet de l’application
● Ils doivent être compréhensibles et maintenables
● Evite le risque de “test smell”
● Non, ce n’est pas qu’un test
● Oui, c’est grave
28. LinkValue
#TheGreatPlaceToGeek
Testez vos cas d’erreurs
● Faites un test pour chaque cas d’erreur
● Vérifiez la nature de la réponse (boolean, exception … )
● Vérifiez le comportement de vos catch dans le cas d’un try/catch
31. LinkValue
#TheGreatPlaceToGeek
Nommer proprement vos tests
● Indiquez la méthode testée dans le nom du test :
“testMyCustomMethod”
● Indiquez le use case dan le nom du test:
“testMyCustomMethodWithSecondParametersMissing”
● Le nom du test doit indiquer son comportement
33. LinkValue
#TheGreatPlaceToGeek
Ne laissez pas de traces
● Ajoutez et supprimez les données de test durant les phases de SetUp
et TearDown
● Ne vous appuyez pas sur les fixtures
● Toujours remettre votre base de donnée à l’état initiale à la fin de
chaque test
34. LinkValue
#TheGreatPlaceToGeek
Gérez vos données
● Les intéractions avec la base de données doivent être testées lors de
tests fonctionnels
● Recréez votre database et vos fixtures avant de lancer vos tests
35. LinkValue
#TheGreatPlaceToGeek
Vos tests sont des classes comme
les autres
● Stockez vos paramètres et dépendances dans des attributs
● Découplez vos méthodes réutilisables (DRY)
● Utilisez les principes SOLID
37. LinkValue
#TheGreatPlaceToGeek
Ne vous focalisez pas sur le code coverage,
mais gardez un ratio de 100% mininum
● 100% ne couvre pas tous les cas de figure
● Moins, c’est la certitude de ne pas couvrir “du tout” une partie du code
● Si moins de 100, alors combien et pourquoi ?
● C’est mettre en péril la valeur qualitative des tests
38. LinkValue
#TheGreatPlaceToGeek
Aucun test n’est futile
● Tester vos Models
● Tester vos getters et setters
● Oui ca sert (principalement en TDD)
● Ca prend cinq minutes à écrire
* attention : aucun test n’est futile! Mais il est inutile de tester le code qui ne
vous appartient pas (librairie tierce/framework …)
39. LinkValue
#TheGreatPlaceToGeek
N’écrivez pas les tests à la fin
● Ecrivez vos tests durant le développement
● Un test est plus simple à écrire quand le code est récent
● Il illustre la mise en pratique du code
● Il complète la doc
● Il limite les “tests smells”
41. LinkValue
#TheGreatPlaceToGeek
Evitez la logique
● Pas de boucle ou de conditions dans un test
● Utilisez les dataProviders pour jouer le test avec plusieurs valeurs
● Simplifiez la compréhension de vos tests
42. LinkValue
#TheGreatPlaceToGeek
Mauvaises idées
● Modifier les paramètres d’environnement pour faire passer certains
tests
● Certains tests ne fonctionnent pas partout
● Mon test unitaire est long car …
● Certains tests sont aléatoirement en échec
47. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test unitaire
● Dans l’exercise,
définissez le
comportement de
votre test
● Dans le verify assurez
vous de la réponse
attendue. Un test doit
contenir au moins une
assertion
48. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test unitaire
● Testez les appels des
méthodes de vos mocks
ainsi que le nombre
d’appels
● Testez également les
paramètres passés en
argument
● Surveillez toutes les
étapes d’avancement de
votre code
49. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test unitaire
● Ne tester que des comportements attendus: inutile de s’assurer qu’une
méthode non utilisée n’est pas appelée
● N’utilisez pas les dataProviders pour tester plusieurs fois le même cas
de figure.
● Faites toujours attention de tester le comportement attendu de votre
code et non le code écrit
50. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test d’intégration
● On ne teste pas le bon
fonctionnement des différentes
couches, on teste leurs
intéractions
● On mock les dépendances
externes (webservice, BDD …)
qui pourrait faire échouer les tests
alors que le code est bon
● On ne vérifie pas le résultat des
dépendances, on vérifie la
réponse de la méthode testée
51. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test d’intégration
● Utilisez intelligemment les mocks,
mais pas trop
● Dans cet exemple l’objet User ne
devrait pas être mocké
● Ne mockez que les classes qui
comportent des dépendances
externes
52. LinkValue
#TheGreatPlaceToGeek
Ecrire un Test d’intégration
● Un test d’intégration intervient dès lors qu’on teste plusieurs classes
● Il ne remplace pas un test unitaire, il le complète
● Les tests d’intégrations sont souvent plus lents et plus fragiles que les
tests unitaires
53. LinkValue
#TheGreatPlaceToGeek
Ecrire un test fonctionnel
● Ne vous appuyez pas sur les
données de fixtures
● Utilisez des transactions pour vos
appels en bdd
● Configurer le lancement de la
transaction dans le setUp et son
rollback dans le tearDown
54. LinkValue
#TheGreatPlaceToGeek
Ecrire un test fonctionnel
● Ne vous occupez pas du code
● Testez uniquement le résultat
● Testez une valeur fixe
seulement si elle est unique
● Ne testez qu’un seul
comportement par test
55. LinkValue
#TheGreatPlaceToGeek
Ecrire un test fonctionnel
Les tests fonctionnels doivent être lancés sur un serveur applicatif dédié et
iso prod.
Pour les dépendances externes (API) :
● Si une version de test existe, configurez et appelez l’api de test
● Si vous appelez une api de prod, connaissez les données retournées
Pour la base de données:
● Appelez une base de données de test
● Utilisez des fixtures pour remplir la base de donnée
58. LinkValue
#TheGreatPlaceToGeek
Process TDD
1. On écrit le test
2. On vérifie que le test échoue
3. On écrit le code le plus vite possible
4. On vérifie que tous les tests soient verts
5. On refactorise le code proprement
63. LinkValue
#TheGreatPlaceToGeek
BDD à la rescousse
● TDD : Incite le développeur à se poser les bonnes questions
● BDD : Behaviour Driven Development.
Aide les différents corps de métiers à se poser les bonnes questions
ensemble
64. LinkValue
#TheGreatPlaceToGeek
Scénariser les tests
● Les tests ne sont plus écrits par les développeurs à partir du cahier
des charges
● Client et développeurs décident ensemble des tests à écrire
● Ecriture de scénario décrivant le comportement de l’application et donc
le comportement à tester
● Utilisation d’un langage commun entre le client et le développeur : le
gherkin
65. LinkValue
#TheGreatPlaceToGeek
Comment tu me causes ?
● Utilisation d’un “ubiquitous language”
gherkin
● Compréhensible par l’ensemble des
métiers
● Utilise la matrice Given/When/Then
pour écriture de scénario
67. LinkValue
#TheGreatPlaceToGeek
Coder un scénario
● Le code reprend les étapes
setUp / exercise / Verify
● BDD permet de coder des
tests fonctionnels
● Ces tests fonctionnels
serviront alors de scénario
pour les tests unitaires
68. LinkValue
#TheGreatPlaceToGeek
BDD + TDD
1. (story) Pour chaque scénario décrivant la fonctionnalité
2. (RED) Lancer le scénario qui va échouer
3. (RED) Définir la première étape
4. (GREEN) Ecrire le code de l’étape pour la faire passer
5. (REFACTOR) Refactorer le code et répéter les étapes
4&5 pour chaque étape jusqu’à ...
6. (GREEN) Le scénario passe
7. (REFACTOR) Refactorer le code de l’application
71. LinkValue
#TheGreatPlaceToGeek
Pour Conclure
● Tester c’est inutile : Seuls les mauvais développeurs ne doutent pas
de leur code
● C’est trop difficile : Non, mais cela demande de l’investissement. Les
bonnes pratiques et les patterns de tests aident pour démarrer
● C’est irréaliste : Regardez autour de vous ! Sur github tout type de
projet et de toute taille les utilisent et fonctionnent. C’est plus régulier
de trouver un projet couvert par les tests
● C’est pas mon job : As tu déjà réfléchis à une reconversion ? Les
tests c’est du code