 Petite présentation, donc mon aimé l'année 10 mois, je suis en informatique depuis plus de 15 ans. Je suis à l'ONF depuis presque 5 ans, donc développeur et maintenant plus Scrum Master. Je trouve ça un peu drôle parce que maintenant que je suis Scrum Master à temps plein, c'est aujourd'hui que je fais une présentation à Montréal-Piton. J'ai rencontré Jean-Philippe à Konfu en février dernier, donc c'est comme ça qu'on m'a demandé de venir ce soir. Alors, j'ai, premièrement, ça va se dérouler en quatre parties. Donc une partie de statistiques qu'on avait fait pendant, bon c'est ça, il y a deux ans. Ensuite, des analyses avec solutions possibles suivies d'actions qui ont été faites et une rétrospective sur cette analyse. Alors, statistiques. C'est donc des tests qui avaient été faits de 2011 à 2013. On voyait juste le nombre de tests qui a augmenté de 700 à 1095. Donc c'est sur Jenkins pour ceux qui avaient reconnu. Donc on roule nos tests sur Jenkins et sur notre build 808. On avait remarqué que c'était 28 minutes et demi pour rouler ces 1095 tests, donc c'était énorme. Donc on se disait qu'il faut qu'on accélère ça, ça n'a pas de sens. Les gens ne roulaient pas leurs tests localement. Donc c'était problématique parce qu'on les roulait seulement sur Jenkins. Et puis à ce moment-là, ça ralentit le processus après que tu pousses et tu as un c-buggy. Donc, durant des tests le plus long, c'était 28 secondes. Donc c'est vraiment long. D'autres statistiques. Bon, ce qu'on peut voir, c'est qu'il y avait 420 tests qui étaient plus qu'une seconde. Et puis bon, jusqu'à 5 tests plus de 20 secondes. Petit rappel pour la différence entre les tests unitaires et les tests d'intégration. Donc test unitaires qui couvrent une petite unité code qui inclut le moins de pattes possibles. On veut faire par exemple un test qui va faire le happy patte, un autre test qui va lancer une exception. Mais on a aussi gardé ça le plus petit possible. Test d'intégration, c'est pour tester les contrats entre les unités. Donc ça se complète bien. Alors, nos années, petite photo que j'ai pris de films de l'ONF. Donc non, on n'a pas fait de tests sur des souris. Ok, donc première étape. On se dit, ok, ici on a une suite de tests unitaires. Mais il faut que ce soit des tests unitaires. On leur trouvait plusieurs tests qu'utilisait le client Django. Le problème avec ça, c'est que ça rendait beaucoup nos tests. Donc le client va couvrir beaucoup plus que ce qu'on a besoin de tester. Donc le URA routing, le request middleware, l'ORM, le rendering, le response middleware. On n'a pas besoin de tout ça pour s'assurer que nos fonctions sont correctes, sont bien écrites. Donc c'est ça, 11 des tests les plus lents qu'avait le client. Ceci, c'est possible. J'ai tout sauté. Oui, c'est ça. Ok. Donc ceci, c'est possible. Créer un test d'intégration équivalent. Déplacer les tests d'intégration dans une suite slow test. Ou plus integration, en tout cas, peu importe comment on le nomme. Appeler les contrôleurs directement pour réduire l'overhead. Donc c'est ça. Entre autres, c'était une des options qu'on a fait après. Je ne sais pas pourquoi c'est comme ça. Attention à la façon d'utiliser cet up-there-down. Alors ici, ça donne un exemple qu'on ne le voit pas directement. Mais il y avait sur 8 des tests les plus lents. Ça faisait un total de 16,166 requêtes à l'ABD. Ce qui ralentissait super gros. Donc évidemment, c'est sûr que si tu as tant de requêtes, oui, ça va être long. Puis en plus, on faisait aussi des... Ici, on allait surgarder des fichiers au fond des films. C'est sûr que c'est long. Donc, solution possible dans ce cas-là. Vous allez voir, il y a des solutions qui se répètent. Donc, utiliser des moques. Plusieurs sortes de moques. Le demi, c'est le plus simple. C'est le minimum nécessaire pour compléter le code. Puis c'est ça. Donc, souvent, c'est remplir les paramètres. Des méthodes, des attributs avec des objets nuls ou vides. L'autre, le stop. Ça, c'est un qu'on utilisait. Un peu plus évoluer que le demi. Donc, il contient, là, si je regarde mes notes, parce que je veux juste être sûr que je vous donne les bonnes définitions. Donc, une implémentation minimale des interfaces et des classes. Les méthodes prennent des arguments, mais ils font rien. Ils font juste envoyer voids ou des valeurs codendues. Le spy, un petit peu plus, en fait, pas plus. Non, c'est ça. Contient pas plus d'implémentation qu'un demi, mais permet d'enregistrer des appels faits sur des paramètres afin de vérifier leur présence plus tard lors des tests unitaires. Le fake. Un objet que les mains font sanité que la version finale, mais de manière plus simple en prenant des raccourcis sans gestion ou presque des erreurs, sans gestion ou presque des erreurs. La seule raison d'utiliser un fake object, c'est quand l'implémentation finale de l'objet n'est pas encore disponible ou est trop lente, ou peut pas être utilisée pour les tests à cause de son instabilité. Le dernier décorateur patch qu'on utilise beaucoup. Donc, pour patcher des objets, seulement dans le scope de la fonction qui est décorée, l'on patching est géré automatiquement, même si une exception est lancée. Donc, ça peut être utilisé dans des statements de WIT ou, bon, c'est ça, décorateur de classe. Donc, deuxième solution possible. Un avantage de setup class tearedown class. Ça, contrairement à setup et tearedown, ça roule une fois par testcase. Donc, ils n'ont pas à chaque fois qu'un test est roulé. Donc, dans setup et tearedown, ça va être roulé à chaque fois qu'un test, au début à la fin d'un test. Mais le setup class et tearedown class, c'est juste au début de tous les tests, puis à la fin des tests. Donc, c'est ça. Les données persistent d'un test à l'autre. Est-ce qu'il y en a qui utilisent ça? Oui. OK. Quand même. Donc, un autre solution, aucun appel à la BD travaille avec des données en lecture qui sont non persistantes. Donc, à la place de ça, c'est le create. Donc, juste de définir la source comme ça. Source, en fait, de langage de 1F, c'est le film. On a un jargon qui est assez spécifique. Donc, ici, donc pour le tearedown, ce qu'on se t'est rendu compte, on a besoin de les faire dans le tearedown, les délites, parce que ça se fait automatiquement. OK. Un secolle ici. Pas mal, trop de choses que le test est en train de faire. Tu sais, déjà, on ne le voit même pas dans la page complète. Donc, ça donne un hint que, peut-être qu'il faut refactorer, tu sais. Il faut trouver de scopes, de concerns différents. Même ici, une variable qui est évident. Évidemment, c'est le data product helper, c'est évident. Non. Donc, comme solution, donc séparation de concern, on veut que le test soit couvre le... il doit couvrir le code limité de la fonction. Donc, vraiment, rester à tester par fonction. Bon, là, j'ai mis avec appel extern limité. Évidemment, il n'y a même pas d'appel externe. Si tu ne peux pas le tester efficacement, c'est que tu as besoin d'un refactoring de ton code. Aussi, utiliser le mock dans un cas plus complexe. Le mock patching, déterminer la façon dont les objets interagissent ensemble. Bon, dans ce cas-ci, encore su par long, ce qu'on voit ici, c'est qu'on essaie de faire un test d'intégration dans un test unitaire. Je ne sais pas si on voit bien, mais non, on ne voit pas super bien. OK. Bon, en gros, il y a un client qui est appelé, on remplit le formulaire avec les données, on fait au fond un achat avec carte de crédit puis fait que c'est... puis encore ici, on ne ne voit pas le test au complet. Est-ce que ça vous arrive d'avoir ça dans votre code des tests qui sont... en ce cas-là aussi des tests d'intégration au lieu d'unitaire déplacer les tests dans une autre suite de test. Donc, pour celui-là, bon, qu'est-ce qu'on voit ici répétition de toutes ces lignes, les 3, les 4 premières lignes. Alors, on n'a pas bien utilisé le setup tear down. Donc, solution de... soit dans un setup class tear down class, ou un setup tear down. Action... c'est pas tout à fait ces actions-là, mais je trouvais ça drôle comme image. Donc, des actions simples qu'on a fait utilisés setup class tear down class. C'est ça, c'est assez simple à refactory. Enlever les tests qui étaient dupliqués. Déplacer des tests d'intégration dans une autre suite de tests. Puis supprimer les délites à l'intérieur des tear down. Des actions un peu plus demandantes. Donc, on a testé le contrôleur directement au lieu d'aller faire les tests de 200, le code de retour de 200. On a utilisé des moques, des patchs, factories. Enlever l'Isabelle à la BD. On a utilisé des données en lecture qui étaient non persistantes. Et puis on a cassé des grosses classes de tests en plus petites. Donc, résultat en ce moment on est avec 4 suites de tests. Dans notre suite de tests, une terre qui roule à peu près 6 minutes. Ce qui est pas mal mieux qu'à 15 ou 30 minutes. C'est sûr qu'il y a d'autres tests qui roulent là. Dans Jenkins, une fois que le premier set de tests est passé, on a un hook pour partir les 3 autres suites de tests. Mais vu que c'est des tests par exemple, il y en a une suite pour les trucs financiers. Un autre qui est sur un système home-made. Donc c'est des tests qui sont au moins touchés. On les a séparés pour ça. Et puis on a aussi notre slow test qu'on appelle plus les tests d'intégration. Et puis résultat et on roule au test localement vu que c'est plus rapide. Ça pourrait être encore plus rapide mais c'est déjà mieux que c'était. Donc en rétrospective une station de micro faders donc un test n'est pas une terre si ça parle à la BD, si ça communique à travers le réseau si ça touche le système des fiers si tu peux pas rouler tes deux tests en parallèle si tu as quelque chose à faire dans les settings dans un fichier config pour le rouler. Donc ces tests-là sont pas mauvais, c'est pas ça qu'on dit mais c'est juste que des fois c'est ça. C'est que tu veux pas les mettre dans ton test unitaire sinon ça va ralentir ton test. Donc c'est ça c'est important de séparer tes vraies unités de test par rapport aux autres. C'est ça qu'on avait fait. Petite note sur le TDD parce que justement en ce moment on est en train de réécrire notre faille de don puis on veut inclure ça dans notre feuille de don et c'est ça qu'en travaillant en TDD ça facilite la bonne écriture des tests unitaires Est-ce qu'il y en a qui sont toujours en TDD qui travaillent toujours en TDD qui travaillent souvent en TDD C'est correct un peu en tout cas fait qu'un petit définition rapide du TDD c'est pensé à ce qu'on veut faire écrire un test qui est chou écrire assez de codes de production pour le faire passer mais pas plus faire ton refactoring et répéter donc c'est simple quand même c'est ça nous autres on en fait déjà un peu mais c'est pas tout le monde puis on essaie d'inculquer ça au nouveau donc un petit conseil ce serait que soyez rigoureux dans votre équipe d'une équipe à l'autre si vous avez plusieurs équipes en pairing en faisant vos revues de codes garder en tête un vrai test unitaire et puis ça va bien se passer donc ça complète ma présentation