<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>TDD - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</title><link>https://jordanchapuy.com/tags/tdd/</link><description>TDD - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Thu, 06 Jan 2022 15:30:00 +0100</lastBuildDate><atom:link href="https://jordanchapuy.com/tags/tdd/" rel="self" type="application/rss+xml"/><item><title>Permis de développer</title><link>https://jordanchapuy.com/posts/2022/01/permis-de-developper/</link><pubDate>Thu, 06 Jan 2022 15:30:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2022/01/permis-de-developper/</guid><description><![CDATA[<p>Un développeur a-t-il besoin d&rsquo;une permission pour écrire des tests ? Pratiquer le Test-Driven Development ? Faire du <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a> ? Travailler en Pair Programming ? Faut-il un permis à l&rsquo;image de la légendaire <em>licence to kill</em> de James Bond ?</p>
<p>Ma réponse est <strong>NON</strong> (sans surprise, comme la plupart des articles qui commencent avec une grande question fermée). Un développeur doit être autonome et décider de lui-même pour ce genre de pratiques. Il n&rsquo;a pas à demander l&rsquo;autorisation à un manager, ni un chef, ni un PO, ni un SM, ni même à un tech lead ou un autre développeur.</p>
<p>Encore moins se voir interdire (anecdote récente lors d&rsquo;un entretien technique, un développeur m&rsquo;a indiqué que son client lui interdisait d&rsquo;écrire des tests parce que ça prenait du temps). Au contraire, il faut promouvoir et pousser ces pratiques aux développeurs et aux équipes.</p>
<h1 id="ça-fait-partie-du-job">Ça fait partie du job</h1>
<p>L&rsquo;écriture de tests, le TDD, le Refactoring, le Pair Programming, et j&rsquo;en passe, ce sont des pratiques répandues dans l&rsquo;industrie. Elles sont reconnues et proviennent de mouvements comme le Software Craftsmanship, l&rsquo;eXtreme programming, ou le Domain Driven Design. Ce n&rsquo;est pas le n-ième <em>nouveau super framework</em> à la mode.</p>
<p>On parle ici de pratiques qui améliorent la qualité du code et du produit, qui facilite le changement, qui permettent de mieux collaborer, de mieux retranscrire le métier. Elles font partie intégrante du métier de développeur.</p>
<p>Un développeur n&rsquo;est pas un exécutant. Il n&rsquo;est pas là juste pour pisser du code. Il a un (grand) rôle à jouer pour concevoir un produit de qualité. Il existe de nombreux ouvrages sur ces pratiques et également sur la posture de développeur. Pour en citer un, <em>Sandro Mancuso</em> en parle très bien dans son livre <em>The Software Craftsman</em>.</p>
<h1 id="just-do-it">Just do it</h1>
<p>Je donnerais comme conseil aux développeurs de faire, de passer à l&rsquo;action, d&rsquo;utiliser ces pratiques. Sans attendre une permission officielle, sans aller chercher une approbation quelconque. Faites-le, tout simplement.</p>
<p>Il y a un proverbe qui dit <code>Il vaut mieux demander pardon que demander la permission</code>. Je l&rsquo;aime bien, et je trouve qu&rsquo;il a du sens dans cette situation. Vous êtes développeur et vous hésitez ? Lancez-vous, essayez, montrez par l&rsquo;exemple. Probablement, quelque chose de bon en sortira et on ne viendra pas vous taper sur les doigts. Ce n&rsquo;est pas parfait ? Vous deviendrez meilleur en continuant d&rsquo;essayer et de vous améliorer.</p>
<p>Rappelons que le développeur a l&rsquo;expertise. Il sait comment travailler, il connaît sa boîte à outils. Mon propos n&rsquo;est pas d&rsquo;enfermer le développeur dans sa vision - il doit rester ouvert, comme tout le monde - mais de lui faire confiance et de lui donner de l&rsquo;autonomie.</p>
<p>Ce qui n&rsquo;empêche pas de le challenger. Et quand on touche à ses limites, à sa zone où il ne maîtrise pas, on se penchera plutôt sur comment former, comment apprendre, comment expérimenter, plutôt que d&rsquo;empêcher.</p>
<h1 id="former-les-équipes">Former les équipes</h1>
<p>Ça fait partie du job, d&rsquo;utiliser ces pratiques, ça fait également partie du job de se former. Elles ne tomberont pas soudainement du ciel. Avis aux développeurs qui doivent faire l&rsquo;effort autant qu&rsquo;aux managers qui doivent investir ;)</p>
<p>On se forme, on forme les équipes, on expérimente, on s&rsquo;améliore en continue. Le retour sur l&rsquo;investissement est positif, on ira plus vite, on délivrera mieux. On veut démarrer un cercle vertueux (on apprend, on améliore le code, on change plus facilement, on livre plus vite, on satisfait davantage l&rsquo;utilisateur) plutôt que vicieux (on empêche, on n&rsquo;apprend pas, le code se détériore, les évolutions deviennent difficiles, on cumule des problèmes, on met du temps à livrer à l&rsquo;utilisateur).</p>
<p>Il y a un tas de moyens pour apprendre. Quelques idées : inviter des personnes à faire un BBL, l&rsquo;intervention de coachs, faire des katas seul ou en groupe, du mob-programming sur le projet, assister à des conférences, lire des livres, etc.</p>
<h1 id="casser-les-idées-reçues">Casser les idées reçues</h1>
<p>Et s&rsquo;il y a du blocage, des interdictions, des permissions à demander pour utiliser ces pratiques ? J&rsquo;essaierais de comprendre pourquoi, de challenger, de rappeler que ça fait partie du job, et de casser certaines idées reçues.</p>
<p>En rappelant la vision, la philosophie de certaines pratiques. Le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a>, ce n&rsquo;est pas un chantier de 3 mois en tunnel. Ce sont des petites étapes, ce sont des améliorations que l&rsquo;on fait au quotidien, qui facilitent le changement, qui améliorent la qualité.</p>
<p><a href="https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/" rel="">L&rsquo;écriture de tests et le TDD, ce n&rsquo;est pas plus long</a>. C&rsquo;est une aide pour le développeur, un guide pour bien retranscrire le métier, le comportement. On obtient en plus de la sérénité quand il faut effectuer des changements. On entre dans des situations où l&rsquo;on ira plus vite.</p>
<p>Le Pair-Programming, ce n&rsquo;est pas juste deux ressources humaines qui se mettent sur un poste pour travailler sur un seul problème à la fois. C&rsquo;est une collaboration poussée, c&rsquo;est un feedback rapide, c&rsquo;est une transmission de connaissances, d&rsquo;informations, c&rsquo;est de l&rsquo;amélioration en continue. Là aussi on entre dans des situations où l&rsquo;on ira plus vite.</p>
<p>On améliore la qualité, on gagne du temps, on gagne de l&rsquo;argent. Trois arguments que l&rsquo;on peut aligner en fonction de l&rsquo;interlocuteur. On pourrait citer en touche finale  <em>Accelerate</em>, un livre qui montre, via une étude sur plusieurs années incluant de très nombreuses entreprises, qu&rsquo;il y a une corrélation entre la performance technique et la performance business.</p>
]]></description></item><item><title>Ce n'est pas plus long de pratiquer le TDD</title><link>https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/</link><pubDate>Sat, 11 Dec 2021 14:35:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/</guid><description><![CDATA[<p>J&rsquo;entends et lis parfois que ça prend du temps d&rsquo;écrire des tests unitaires et de pratiquer le Test-Driven Development. Que c&rsquo;est bien plus long que de ne pas en faire. Je ne suis pas en phase.</p>
<p>J&rsquo;ai la conviction que ça ne prend pas forcément plus de temps de travailler en TDD. On est sensiblement sur la même longueur, parfois même plus rapide parce que ça nous guide. On est très loin du laïus <em>&ldquo;c&rsquo;est une perte de temps&rdquo;</em>, surtout lorsque l&rsquo;on regarde sur différents horizons de temps.</p>
<p>Il n&rsquo;y a d&rsquo;ailleurs pas que le temps qui entre en jeu, d&rsquo;autres bénéfices gravitent autour de l&rsquo;écriture des tests et de la pratique du TDD. Pour étayer mes affirmations, j&rsquo;ai envie d&rsquo;en parler à travers plusieurs prismes.</p>
<h2 id="jai-une-mauvaise-utilisation-du-tdd">J&rsquo;ai une mauvaise utilisation du TDD</h2>
<p>Pour le premier prisme, je prends un développeur qui pratique le TDD mais qui l&rsquo;utilise mal, qui ne le maîtrise pas. Je commence par ce postulat parce que c&rsquo;est sûrement là qu&rsquo;il y a le plus de confusion et de mécompréhension. Les personnes qui ne maîtrisent pas l&rsquo;art de tester et du TDD se forgent un avis sur la base d&rsquo;une expérience incomplète.</p>
<p>Qu&rsquo;est-ce que c&rsquo;est, <em>ne pas maîtriser</em> ? Penser que ça se résume à <em>écrire un test en premier</em>, que c&rsquo;est purement de la <em>technique</em> (versus métier), ou que ça se limite à suivre le <em>Red-Green-Refactor</em>, par exemple.</p>
<p>En adoptant une mauvaise pratique, on va se mettre des bâtons dans les roues. On va vouloir tout mocker, on va tester l&rsquo;implémentation, on ne va pas faire de petites étapes, etc. Résultat, on va trouver ça plus long. On va peut-être préférer ne pas faire de TDD, finalement. C&rsquo;est plus long et il y a un tas de trucs chiants à faire, pourquoi s&rsquo;emmerder.</p>
<p>Dans ce contexte, la méthode est mal comprise et mal appliquée. C&rsquo;est probablement plus long de pratiquer le TDD, oui. Mais peut-on juger la méthode dans ces conditions ? J&rsquo;y répondrais par une autre question. Est-ce qu&rsquo;une voiture est lente parce qu&rsquo;on roule avec le frein à main ? Ou parce qu&rsquo;on ne sait pas comment passer les vitesses ? Non.</p>
<p>=&gt; Oui, une mauvaise application du TDD peut demander davantage de temps. Non, dans ce contexte, c&rsquo;est inexact de déduire qu&rsquo;une bonne pratique du TDD prend du temps.</p>
<h2 id="japprends-le-tdd">J&rsquo;apprends le TDD</h2>
<p>Dans ce second prisme, j&rsquo;introduis une nuance : un développeur qui s&rsquo;exerce à pratiquer le TDD mais qui ne le maîtrise pas encore parce qu&rsquo;il est en phase d&rsquo;apprentissage. La différence avec le premier prisme ? Il a conscience de la bonne pratique du TDD et il s&rsquo;améliore pour y arriver. Il ne va pas mal faire tout en supposant qu&rsquo;il maîtrise la méthode.</p>
<p>Disons les choses. Le TDD, c&rsquo;est difficile. Ça demande du temps pour le maîtriser. Ça demande de s&rsquo;entraîner, de répéter, de s&rsquo;améliorer. Mais pour autant, c&rsquo;est la phase d&rsquo;apprentissage qui requiert du temps. Ce n&rsquo;est pas l&rsquo;application de la méthode elle-même. Encore une fois, juge-t-on la vitesse d&rsquo;une voiture avec un pilote qui apprend à passer les vitesses ? Non.</p>
<p>Ok. Et durant cet apprentissage alors, à quel point ça prends du temps de faire du TDD ? Ça dépend. Ça dépend du contexte, ça dépend du niveau de compétence que l&rsquo;on a acquis à cet instant.</p>
<p>Il y a des situations où l&rsquo;on ne sera pas encore à l&rsquo;aise, on devra ralentir pour bien faire, on prendra davantage de temps sur le moment. À l&rsquo;inverse, il y a des situations où l&rsquo;on sera guidé par le TDD et où l&rsquo;on obtiendra plus rapidement un bon résultat. On va commencer à bénéficier des effets positifs (j&rsquo;en parlerais après).</p>
<p>=&gt; Oui, l&rsquo;apprentissage du TDD demande du temps. Non, on ne peut pas dire que la pratique elle-même, une fois maîtrisée, prend du temps.</p>
<h2 id="jécris-mes-tests-après">J&rsquo;écris mes tests après</h2>
<p>Je me mets maintenant dans le prisme d&rsquo;un développeur qui écrit ses tests après coup. Que se passe-t-il si je me mets à faire du TDD ? On pourrait se dire que l&rsquo;on va prendre davantage de temps, on écrit déjà des tests, pourquoi se compliquer la vie à s&rsquo;ajouter une méthode ?</p>
<p>Eh bien, dans ce contexte, pratiquer le TDD sera probablement plus efficace et plus rapide. Le TDD va guider l&rsquo;écriture de l&rsquo;implémentation. On obtiendra une meilleure conception, on avancera par petites étapes et on sera guidé par le comportement métier. Ce sera une aide pour écrire de meilleurs tests et un meilleur code.</p>
<p>De fait, on s&rsquo;évitera les pièges d&rsquo;écrire du code non-testable, d&rsquo;en faire trop, ou de ne pas correctement retranscrire le métier, comme on pourrait le faire en écrivant les tests a posteriori.</p>
<p>En écrivant les tests après, on subit l&rsquo;implémentation. Et plus on attend pour tester, plus on subit. Il y aura davantage de changements à effectuer, le coût va augmenter. Le refactoring sera d&rsquo;ailleurs difficile ; les tests ne sont pas écrits, on n&rsquo;a pas encore notre filet de sécurité en place.</p>
<p>=&gt; Non, ce n&rsquo;est pas plus long de pratiquer le TDD lorsque l&rsquo;on écrit déjà des tests a posteriori. C&rsquo;est un gain de temps, et en plus, un gain de qualité.</p>
<h2 id="je-ne-teste-pas">Je ne teste pas</h2>
<p>Je termine avec un dernier prisme qui n&rsquo;en ait pas moins intéressant : celui du développeur qui ne teste pas. Alors là, réflexe, on va se dire que c&rsquo;est bien plus long. Non seulement, il faut écrire du code supplémentaire (les tests), et en plus, il faut se coltiner une discipline stricte. On va perdre du temps, non ? Je propose de regarder sous deux horizons de temps.</p>
<h3 id="court-terme">Court terme</h3>
<p>À court terme, sur l&rsquo;instant, le TDD va nous guider. C&rsquo;est une de ses principales forces. Il nous guide pour concevoir le code de production, l&rsquo;implémentation. Il nous guide pour retranscrire le métier. Il nous offre une boucle de feedback extrêmement rapide pour créer et améliorer.</p>
<p>On prends le temps de bien faire et de réfléchir, mais pour autant, ce n&rsquo;est pas forcément plus long. Parce qu&rsquo;on se concentre sur l&rsquo;essentiel en progressant par petites étapes, parce qu&rsquo;on est guidé pour coder l&rsquo;implémentation, parce qu&rsquo;on a un feedback rapide contrairement aux tests manuels.</p>
<p>La pratique du TDD ne va pas seulement nous faire écrire des tests avant de coder, elle va nous aider à coder, à concevoir. Au final, on ralentit tout en gagnant du temps, pour mieux faire. On passe sensiblement le même temps à développer notre fonctionnalité.</p>
<p>Dans certains contextes, on est plus rapide, parce qu&rsquo;on se serait perdu en chemin sans le TDD, parce qu&rsquo;on aurait fait trop compliqué ou parce qu&rsquo;il y a beaucoup de logique. On perd vite du temps à explorer sans test et sans guide. Dans quelques autres contextes, ça peut être plus long de pratiquer le TDD, mais c&rsquo;est sans compter les effets obtenus à plus long terme.</p>
<h3 id="moyen-et-long-terme">Moyen et Long terme</h3>
<p>À moyen et long terme, on va obtenir de nouveaux bénéfices grâce à la pratique du TDD. Les tests vont couvrir notre code et vont faciliter le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a> et réduire les régressions. On va gagner du temps.</p>
<p>La facilité de faire du refactoring va aider à améliorer continuellement le système. On va le maintenir et le faire évoluer plus facilement. On va le changer facilement. On va gagner du temps.</p>
<p>On aura du code et des tests qui reflètent mieux le métier et les cas d&rsquo;utilisations. On va mieux comprendre notre système. On va mieux échanger avec les autres. On va gagner du temps.</p>
<hr>
<h1 id="bref">Bref</h1>
<p>Au final, en regardant à travers ces différents prismes, on peut observer que les situations où un développeur trouve que c&rsquo;est plus long de pratiquer le TDD est peut-être à décorréler de la méthode elle-même. Souvent parce qu&rsquo;elle n&rsquo;est pas encore maîtrisée.</p>
<p>Dès lors qu&rsquo;on a une bonne pratique du TDD, des bénéfices apparaissent immédiatement, à court terme. La force que le TDD propose pour guider et donner du feedback rapide est assez puissante pour être d&rsquo;une grande aide pour le développeur tout en ne faisant pas <em>perdre de temps</em>.</p>
<p>Ces effets s&rsquo;accentuent à plus long terme, et d&rsquo;autres viennent s&rsquo;ajouter. On y voit un cercle vertueux d&rsquo;amélioration continue. Ce n&rsquo;est plus juste une question de temps, on y gagne sur plusieurs niveaux.</p>
]]></description></item><item><title>Pourquoi veut-on rendre un test unitaire indépendant ?</title><link>https://jordanchapuy.com/posts/2021/09/pourquoi-veut-on-rendre-un-test-unitaire-independant/</link><pubDate>Wed, 29 Sep 2021 08:50:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/09/pourquoi-veut-on-rendre-un-test-unitaire-independant/</guid><description><![CDATA[<p>L&rsquo;indépendance n&rsquo;existe pas uniquement dans certaines régions de France ou dans un film avec Will Smith. Il se trouve aussi dans les tests unitaires. Lorsque vous écrivez des tests, il y a un moment qui arrive où vous souhaitez être indépendant de quelque chose. Vous allez naturellement casser cette dépendance et injecter autre chose pour remplacer ce qui gêne.</p>
<p>Ce n&rsquo;est cependant pas une décision à prendre à la légère. Certaines raisons sont parfaitement justifiées, alors que d&rsquo;autres peuvent nuire au projet. Pourquoi a-t-on besoin de casser une dépendance dans certains tests ? Et de quoi veut-on être indépendant ? À quoi faut-il faire attention ? C&rsquo;est de tout ça dont j&rsquo;ai envie de parler aujourd&rsquo;hui.</p>
<figure>
</figure>

<h1 id="quest-ce-qui-nous-pose-problème-">Qu&rsquo;est-ce qui nous pose problème ?</h1>
<p>Commençons par le commencement. On veut savoir pourquoi rendre un test indépendant, regardons du côté des problèmes auxquels cette envie d&rsquo;indépendantisme répond.</p>
<h2 id="test-déterministe">Test déterministe</h2>
<p>Avoir des tests qui échouent sans raison apparente à première vue, c&rsquo;est embêtant. Encore plus lorsque ça semble être aléatoire. Et parfois, on a un passage au rouge du jour au lendemain, ce qui nous vaut la célèbre phrase &ldquo;ça marchait avant&rdquo;. Un test devrait avoir une intention claire et n&rsquo;avoir qu&rsquo;une seule raison d&rsquo;échouer. On n&rsquo;a pas envie de se lancer dans une session de debug pour comprendre ce qu&rsquo;il se passe.</p>
<p>Alors qu&rsquo;est-ce qui peut bien causer ces problèmes ? Un autre test. Ce bienfaiteur qu&rsquo;est le test peut en effet être une source d&rsquo;ennuis pour d&rsquo;autres tests. Lorsqu&rsquo;on lance un ensemble de tests, l&rsquo;environnement et la mémoire sont partagés entre eux. Si deux tests lisent et écrivent dans un même endroit, ils vont éventuellement affecter le résultat de l&rsquo;autre. Vous voyez où je veux en venir ? Base de données, fichiers, singletons, variables globales, &hellip; Tout ça représente une zone partagée et peut créer un lien de dépendance entre deux tests.</p>
<p>On arrive donc à notre première et principale raison. <strong>Pourquoi rendre un test indépendant ? Pour éviter un effet de bord venant d&rsquo;un autre test.</strong> C&rsquo;est dans ce but que l&rsquo;on va casser une dépendance envers une base de données, un système de fichiers ou un singleton. Et que l&rsquo;on mettra une fausse implémentation, avec un base de données en mémoire par exemple, pour avoir un état déterministe.</p>
<p>C&rsquo;est d&rsquo;ailleurs une autre raison, être déterministe. <strong>On veut rendre un test indépendant pour obtenir toujours le même résultat.</strong> Du côté des causes, on retrouvera celles vues précédemment et on peut notamment y ajouter d&rsquo;autres éléments perturbateurs comme les requêtes HTTP, la date du jour, les fonctions aléatoires (quoi de mieux qu&rsquo;un bon <code>random()</code> pour avoir un résultat imprévisible ? :p). Ce sont des sources qu&rsquo;on ne contrôle pas. Mais pour être déterministe, il faut les contrôler : on cassera alors les dépendances afin de les remplacer. Ou peut-être que l&rsquo;on s&rsquo;orientera vers la création de fonctions pures.</p>
<h2 id="test-rapide">Test rapide</h2>
<p>Ajoutons un autre problème, sinon ce n&rsquo;est pas marrant. Une suite de tests lente à exécuter est assez fâcheux. Les tests unitaires nous guident dans la conception et parfois nous rattrapent lors de sorties de route. On a besoin d&rsquo;un feedback rapide, et encore plus lorsque l&rsquo;on pratique le TDD.</p>
<p>On aura une nouvelle fois les mêmes fautifs. Feraient-ils preuve d&rsquo;intelligence ? On se le demande, mais en tout cas ça nous arrange puisqu&rsquo;il n&rsquo;y a pas de centaines de causes différentes. Principalement, tout ce qui accède au réseau, aux internets, ralentira fortement vos tests. On peut rester dans la centaine de millisecondes comme dépasser aisément la barre des secondes. C&rsquo;est sûrement la source la plus lente. Viennent ensuite les bases de données et le système de fichiers. Unitairement, le temps est peut-être faible, mais quand on dézoom et qu&rsquo;on regarde le cumul sur l&rsquo;ensemble des tests, ça devient (trop) long.</p>
<p>On en vient à notre dernière raison. <strong>On veut rendre un test indépendant pour qu&rsquo;il soit rapidement exécuté.</strong> Là encore, on cassera éventuellement des dépendances qu&rsquo;on substituera par quelque chose répondant immédiatement.</p>
<h2 id="couper-les-ponts">Couper les ponts</h2>
<p>Si on résume en une phrase, on souhaite rendre un test indépendant afin d&rsquo;éviter qu&rsquo;il soit affecté par les autres tests, pour être déterministe, et pour être rapide. Voilà. Ce sont les raisons principales. Pas besoin d&rsquo;aller chercher plus loin et d&rsquo;isoler complètement un test.</p>
<p>Un autre moyen d&rsquo;entrevoir ces raisons est de regarder du côté des <a href="https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/" rel="">principes FIRST</a>. Ce sont des principes pour guider l&rsquo;écriture des tests, et je trouve qu&rsquo;ils reflètent bien les besoins d&rsquo;indépendance. On parle de rapidité d&rsquo;exécution (F pour Fast), de test indépendant des autres tests (I pour Independent) et de résultat déterministe (R pour Repeatable).</p>
<h1 id="quelques-mauvaises-compréhensions">Quelques mauvaises compréhensions</h1>
<p>Maintenant que nous avons bien en tête les raisons qui motivent les tests à devenir indépendant, revenons sur quelques mauvaises compréhensions. C&rsquo;est essentiel d&rsquo;en parler, car il peut y avoir un impact fort : tests fragiles, maintenance lourde, démotivation des développeurs.</p>
<h2 id="system-under-test">System Under Test</h2>
<p>Quand on parle de <em>SUT</em>, on parle de <em>SYSTEM Under Test</em>. Ce n&rsquo;est ni <em>Class Under Test</em> ni <em>Fonction Under Test</em>. C&rsquo;est très important. Le système, ce peut être une fonction, ou une classe, ou un ensemble de classes et de fonctions. Peu importe, on va tester l&rsquo;ensemble et tout ce qu&rsquo;il y a derrière. On peut voir ça comme un module, ou une boîte noire - <strong>on teste toute la boîte depuis notre point d&rsquo;entrée</strong>.</p>
<p>On ne cherche pas à isoler le système que l&rsquo;on teste des autres classes et fonctions qu&rsquo;il utilise. On rend le test indépendant, oui, mais pas la classe. On s&rsquo;en tiendra aux raisons évoquées plus haut pour casser des dépendances. C&rsquo;est parfaitement ok qu&rsquo;une méthode que l&rsquo;on teste appelle d&rsquo;autres classes, qui appelleront aussi d&rsquo;autres classes.</p>
<h2 id="heavy-mocking">Heavy mocking</h2>
<p>En comprenant bien ce qu&rsquo;est le <em>SUT</em> et ce qu&rsquo;il faut rendre indépendant, on s&rsquo;évite au passage la sur-utilisation de mocks. On ne va pas essayer de tout isoler et donc de tout mocker.</p>
<p><strong>Le problème avec les mocks, c&rsquo;est qu&rsquo;ils connaissent trop les détails de l&rsquo;implémentation</strong>. Si on change notre implémentation (on a une meilleure idée, on fait du refactoring), on va casser les tests. Les assertions vont être fausses et c&rsquo;est normal, le mock vérifie la mécanique interne.</p>
<p>La sur-utilisation des mocks va entraîner des problèmes en cascade : on couple les tests à l&rsquo;implémentation, on a du mal à faire du refactoring, le code devient difficile à changer, le développeur se démotive, il y a moins de tests, moins de qualité, fin. Vraiment, on ne veut pas coupler les tests à l&rsquo;implémentation :)</p>
<h1 id="comportement">Comportement</h1>
<p>Ça me fait une bonne ouverture pour terminer. Ce que l&rsquo;on veut tester, c&rsquo;est le comportement. Quand on fait des applications, c&rsquo;est pour répondre à un besoin métier. C&rsquo;est ça que l&rsquo;on veut tester. On se limitera à enlever les dépendances gênantes pour les tests unitaires. <strong>Testez le comportement plutôt que les détails de l&rsquo;implémentation</strong>.</p>
<figure>
</figure>

<p><em>Crédits photos : Anne Nygård, Richard Lee.</em></p>
]]></description></item><item><title>Apprendre en pratiquant avec des katas de code</title><link>https://jordanchapuy.com/posts/2021/08/apprendre-en-pratiquant-avec-des-katas-de-code/</link><pubDate>Mon, 23 Aug 2021 15:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/08/apprendre-en-pratiquant-avec-des-katas-de-code/</guid><description><![CDATA[<p>Lorsque j&rsquo;ai appris à faire du vélo, j&rsquo;ai commencé à en faire dans mon jardin, dans la Drôme. Mon vélo avait deux petites roulettes sur la roue arrière, ça m&rsquo;aidait beaucoup. On peut dire que j&rsquo;étais dans un cadre sécurisant : à l&rsquo;intérieur de mon jardin, avec peu de risque de chute et sans circulation de véhicules. J&rsquo;ai pédalé des heures et des heures pour améliorer ma maîtrise. J&rsquo;ai appris par la pratique, en répétant, en essayant, en m&rsquo;améliorant. J&rsquo;étais à l&rsquo;aise, bien plus qu&rsquo;à Paris lorsque j&rsquo;utilisais les anciens Vélib - les tanks.</p>
<p>Les katas de code forment un moyen très intéressant pour apprendre par la pratique. On découvre, on explore, on essaie, on répète, on améliore. Bref, on apprend. Et à l&rsquo;image du vélo à roulette, on est dans un cadre sécurisé et simplifié.</p>
<p><strong>Je fais des katas pour apprendre de nouvelles choses.</strong> Ces <em>choses</em> peuvent être très variées. Des langages par exemple. Je me suis amusé avec Kotlin, Typescript, Clojure, Elixir, Elm ainsi que F# récemment. Des langages très <strong>hétérogènes</strong>. Ça me permet d&rsquo;agrandir ma vision, d&rsquo;obtenir de nouvelles connaissances et d&rsquo;être moins lié à un éco-système ou à une façon de faire. Via les katas de code, j&rsquo;apprends aussi des concepts comme CQRS et Event-Sourcing, ou le Mutation Testing. Je m&rsquo;entraîne à toujours mieux concevoir mon code, le rendre plus simple, plus compréhensible, à mieux retranscrire le métier.</p>
<p>Avec les katas, <strong>je répète des gestes pour parfaire ma maîtrise</strong>. Le mot kata est d&rsquo;ailleurs un terme japonnais qui vient des arts martiaux. Le but est de travailler des techniques en toute sécurité en répétant des gestes. On apprend par la répétition dans un environnement dédié à l&rsquo;apprentissage (ce n&rsquo;est pas un vrai combat). J&rsquo;utilise les katas de code pour répéter l&rsquo;écriture de tests, le TDD, le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" target="_blank" rel="noopener noreffer">Refactoring</a>. <strong>C&rsquo;est par une longue pratique et des contextes différents que l&rsquo;expérience vient.</strong> On n&rsquo;acquiert pas une maîtrise après avoir lu un article et une vidéo sur YouTube. Je vais parfois faire plusieurs fois le même kata de manière différente, et parfois répéter la même manière mais sur des katas différents.</p>
<p><strong>La nature éphémère et simple d&rsquo;un kata de code apporte un cadre favorisant l&rsquo;apprentissage</strong> (à opposer avec un projet perso ou la production en entreprise). Je peux expérimenter comme bon me semble, je peux recommencer autant que je veux, je peux prendre le temps que je veux. Je choisis mes contraintes. Il n&rsquo;y a pas de mise en danger ni d&rsquo;impératif.</p>
<p><strong>Il n&rsquo;y a pas d&rsquo;âge pour faire des katas de code</strong>. <em>Je suis Junior, je suis Senior, je sors d&rsquo;école, j&rsquo;ai 12 années d&rsquo;expériences&hellip;</em> En fait, la bonne affirmation serait plutôt <strong>j&rsquo;ai toujours à apprendre et à approfondir</strong>. Que ce soit dans notre domaine de prédilection ou dans d&rsquo;autres qui restent à explorer. Je fais partie d&rsquo;un groupe de kata pour coder et réfléchir ensemble, composé de développeurs expérimentés. Malgré tout, on continue d&rsquo;apprendre et de se casser quelques dents. Et on aime ça.</p>
<p>Je fais des katas seul, pour explorer ce que je veux, quand je le veux. Et je fais également <strong>des katas en groupe pour démultiplier mon apprentissage</strong>. En mob-programming, nous partageons, nous discutons, nous confrontons des visions, nous essayons différentes solutions. Nous nous ouvrons et nous apprenons les uns des autres.</p>
<p>C&rsquo;est tout ça, pour moi, la magie des katas. C&rsquo;est un très bon levier d&rsquo;apprentissage et terrain de jeu. Bien sûr, ce n&rsquo;est ni le seul moyen d&rsquo;apprendre, ni suffisant. Je vais aussi lire des livres pour obtenir plus de théorie et de profondeur, assister à des conférences, pratiquer sur des projets réels, etc.</p>
<h2 id="votre-prochain-kata">Votre prochain kata</h2>
<p>J&rsquo;en arrive à la fin de ce que je voulais raconter. Il me reste à vous partager des liens pour trouver vos futurs katas de code ainsi qu&rsquo;une petite sélection de ceux que j&rsquo;apprécie, puis je retournerais m&rsquo;amuser.</p>
<p>Je ne peux parler de kata sans mentionner Emily Bache. Coach et auteur du livre <em>Coding Dojo Handbook</em>, Emily possède <a href="https://github.com/emilybache" target="_blank" rel="noopener noreffer">un compte GitHub</a> qui fourmille de katas (un grand merci à elle). Elle les prépare et les utilise pour accompagner des équipes; vous en aurez pour tous les goûts.</p>
<p>Certains sites et pages GitHub recensent également des katas. En voici trois que j&rsquo;utilise régulièrement pour piocher des sujets : <a href="https://codingdojo.org/kata/" target="_blank" rel="noopener noreffer">Coding Dojo</a>, <a href="https://kata-log.rocks/" target="_blank" rel="noopener noreffer">Kata-log</a> et <a href="https://github.com/gamontal/awesome-katas" target="_blank" rel="noopener noreffer">Awesome Katas</a>. Et n&rsquo;oubliez pas votre moteur de recherche préféré, il se fera un plaisir de vous en faire découvrir d&rsquo;autres.</p>
<p>En ce moment, je suis sur un kata bien sympa qui reprend les mécaniques d&rsquo;un jeu de carte dans le style de Hearthstone, le <a href="https://github.com/bkimminich/kata-tcg" target="_blank" rel="noopener noreffer">Trading Card Game</a>. J&rsquo;aime également le Bank Account, le Mars Rover, le Game of Life et le GildedRose. Ils font partie de mes classiques. Ils sont simples et très efficaces. Ils permettent de s&rsquo;amuser avec de multiples concepts différents et d&rsquo;expérimenter plusieurs solutions.</p>
<p>Vous voilà avec de nombreuses raisons de vous lancer, et toute une liste de katas potentiels. Bon apprentissage !</p>
]]></description></item><item><title>Automatically run tests when a change occurs</title><link>https://jordanchapuy.com/posts/2020/06/automatically-run-tests-when-a-change-occurs/</link><pubDate>Thu, 04 Jun 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/06/automatically-run-tests-when-a-change-occurs/</guid><description><![CDATA[<p>I would like to talk to you about unit tests and how you can automatically run them as soon as you modify code. I regularly use the Test-Driven Development approach when I write code for a project or when doing a code kata. Sometimes I write a little bit too much before running tests again, and when tests turn red, I’m telling myself “Oh! But since when was I wrong?”.</p>
<p>I am jealous of the experience Visual Studio offers with C# and the <a href="https://docs.microsoft.com/en-us/visualstudio/test/live-unit-testing" target="_blank" rel="noopener noreffer">Live Unit Testing</a> feature. Each line of the code is decorated with a symbol indicating if it is covered by passing tests or failing tests, in real-time. Awesome. I need something like that.</p>
<p>I started by searching a similar tool for the languages I use. Then I created a simple script, which runs a command after each file change. Finally, I found a really nice tool for file change monitoring. It is powerful, cross-platform, and open-source. And that’s what I want to talk to you about.</p>
<figure>
</figure>

<hr>
<h1 id="watch-my-changes-">Watch my changes! 🔍</h1>
<p>One way to improve the feedback given by our tests is to know immediately if a change breaks a test. To achieve this goal, we have to continually run tests. The more often we run the tests, the smaller the failing piece of code will be. Ideally, tests should be run after each change. But we can easily forget, or it can be cumbersome.</p>
<p>So we need a way to monitor files and automatically execute a command if there is a change. Some languages and tools offer a built-in way to do that. For example:</p>
<ul>
<li>Kotlin through Gradle &gt; <code>gradle test —-continuous</code></li>
<li>Elm with elm-test &gt; <code>elm-test --watch</code></li>
</ul>
<p>But what if the programming language and tool we are using do not have a watch option? This is where <em>fswatch</em> comes in.</p>
<hr>
<h1 id="fswatch-">fswatch 📡</h1>
<p>Open-source and cross-platform, <em>fswatch</em> is a great tool to monitor file change. It provides recursive directory monitoring, filtering, and supports many OS-specific APIs such as <em>kevent</em>, <em>inotify</em>, and <em>FSEvents</em>.</p>
<p>By using these low-level APIs, <em>fswatch</em> is able to detect any changes in your specified paths and to send informations to another command. The tool is good enough to throttle the execution of the command: it will wait for the user to stop editing the code.</p>
<p>For more information about features or how to install it, please take a look at the GitHub repository.</p>
<p><a href="https://github.com/emcrisostomo/fswatch" target="_blank" rel="noopener noreffer">https://github.com/emcrisostomo/fswatch</a></p>
<h2 id="usage">Usage</h2>
<p>In most cases, you simply want to fire a command as soon as a change is detected in a folder. It’s as simple as this line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or YOUR_PATHS <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> YOUR_COMMAND
</span></span></code></pre></div><p><em>fswatch</em> accepts a list of paths to monitor. The <code>o</code> option asks the tool to group changes by batch, and the <code>r</code> option stands for watching subdirectories recursively. Events are then sent through <code>xargs</code> to your command. Here is an example for swift, observing one folder:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Project <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> swift <span class="nb">test</span>
</span></span></code></pre></div><p>Note that <em>fswatch</em> will run until you stop it, by pressing <code>Control + Z</code> on macOS or <code>Control + C</code> on Linux for example. But that’s what we want, run indefinitely regardless of the test results.</p>
<figure><figcaption>
            <p><em>Screenshot from a terminal executing fswatch.</em></p>
        </figcaption>
</figure>

<hr>
<h1 id="going-further-">Going further 🚀</h1>
<p>So, you got the basics. Now we will see how to improve it.</p>
<h2 id="choose-carefully-the-files-to-monitor">Choose carefully the files to monitor</h2>
<p>You may want to not run your tests for every kind of file changed. A change in an image or in a <em>temp</em> folder probably does not interest you. Observing the right files allows you to run tests only if an impacting change occurs. It can also prevent you from going into an infinite loop.</p>
<p>I had a case where build files were generated after each test, so that triggered the watch, and run tests again, and changes appear, and… this story will never end. The easiest solution for me was to specify multiple sub-directories as input to fswatch` instead of the whole project folder. Remember that you can set multiple paths.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Sources ./Tests <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> swift <span class="nb">test</span>
</span></span></code></pre></div><p>The other way is to include or exclude paths matching a regex. According to the <em>fswatch</em> manual, you can set options like <code>-i, --include</code> and <code>-e, --exclude</code> for that.</p>
<h2 id="create-a-script">Create a script</h2>
<p>Sometimes, the command you want to fire for each change is long and requires a lot of parameters. It may even be composed of multiple commands. In that case, I recommend you to decompose this step and to create a script to run your tests.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Sources ./Tests <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> run-tests.sh
</span></span></code></pre></div><p>Better, isn’t it? But we can still improve that. We can avoid typing that long line every time we start working. You see me coming, we’ll make a second script that will do it.</p>
<p><code>live-tests.sh</code></p>
<h2 id="keep-it-visible">Keep it visible</h2>
<p>Now that we have a real-time feedback, we want to see it. It would be a shame to have it hidden in the background. Good news, it is quite easy to keep a terminal in the foreground. Perhaps your favorite editor has already a panel with a terminal, and you just have to show it. Visual Studio Code, for instance.</p>
<p>Some editors like Sublime Text do not have a terminal panel by default, but you can add it with a plugin or extension. And if that’s not possible, you still have the option to put the terminal on a second screen, if you have one, or to reduce your editor window and put a terminal at the left, right, or bottom of it.</p>
<figure><figcaption>
            <p><em>Screenshot from Visual Studio Code with a terminal panel at the bottom.</em></p>
        </figcaption>
</figure>

<hr>
<p>You have everything you need to get started. Monitoring files is at your hands. Enjoy the continuous and real-time feedback of your unit tests.</p>
]]></description></item><item><title>Playgrounds: Speed up your tests feedback in Swift</title><link>https://jordanchapuy.com/posts/2020/05/playgrounds-speed-up-your-tests-feedback-in-swift/</link><pubDate>Mon, 04 May 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/05/playgrounds-speed-up-your-tests-feedback-in-swift/</guid><description><![CDATA[<p>Playgrounds was released in September, 2016. It’s a powerful environment integrated in Xcode to code in real-time in Swift. Using Playgrounds is a great way to learn, experiment, and quickly prototype.</p>
<p>This is particularly interesting when comparing its speed with an iOS or macOS project. Compiling such a project takes tens of seconds or even several minutes. Running tests is therefore also slowed down.</p>
<p>Test-Driven Development is about getting feedback quickly. Wouldn’t it be interesting to get real-time results? Let’s see how we can leverage Playgrounds to write and run unit tests in Swift.</p>
<figure>
</figure>

<hr>
<h1 id="writing-unit-tests">Writing unit tests</h1>
<p><a href="https://developer.apple.com/documentation/xctest" target="_blank" rel="noopener noreffer">XCTest</a>, the Apple framework for unit testing, is available through Playgrounds. Writing unit tests in Playgrounds is exactly similar to writing them inside a project with a unit test target. You just have to import <code>XCTest</code> and to write unit tests inside a test case class:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">import</span> <span class="nc">XCTest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloServiceTests</span><span class="p">:</span> <span class="n">XCTestCase</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testMakeMessage</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Arrange</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="mi">1587301244</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">dateProvider</span> <span class="p">=</span> <span class="n">FakeDateProvider</span><span class="p">(</span><span class="n">now</span><span class="p">:</span> <span class="n">now</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">service</span> <span class="p">=</span> <span class="n">HelloService</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">dateProvider</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Act</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">message</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">makeMessage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Assert</span>
</span></span><span class="line"><span class="cl">        <span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s">&#34;1587301244 - Hello.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It does not change your habits. You write a unit test, instantiate a class, call a method and assert a result as you are used to. You can add as many tests and test cases as you want. See? Simple.</p>
<hr>
<h1 id="running-unit-tests">Running unit tests</h1>
<p>The difference with a classic unit test target starts here, but that does not mean it will be complicated. Rather, it’s very simple. The solution fits in one line of code. Here it is:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="n">HelloServiceTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></div><p>Results of unit tests will appear in the console. These are the same logs you can find in Xcode. Each time you are changing the code, unit tests will be automatically launched again and new logs will be printed.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Suite ‘HelloServiceTests’ started at 2020–04–30 16:31:24.776</p>
<p>Test Case ‘-[HelloServiceTests testMakeMessage]’ started.</p>
<p>Test Case ‘-[HelloServiceTests testMakeMessage]’ passed (0.017 seconds).</p>
<p>Test Suite ‘HelloServiceTests’ passed at 2020–04–30 16:31:24.794.</p>
<p>Executed 1 test, with 0 failures (0 unexpected) in 0.017 (0.018) seconds</p>
</div>
        </div>
    </div>
<p>But, why do we need this line? With an Xcode project, to run a test, we are usually pressing <code>Cmd + U</code> or choosing <code>Product &gt; Test</code> from the menu. Behind the scene, the test target gathers every test case and test method while we are creating them. This list is then given to the test runner which will execute every test listed.</p>
<p>In a playground, this process does not exist really. We have to manually create a test suite (something containing all of the tests) and run it. If you want to know more about the behaviors of unit testing frameworks, I recommend you to take a look at <a href="http://xunitpatterns.com/XUnit%20Basics.html" target="_blank" rel="noopener noreffer">xUnitPatterns.com</a>.</p>
<h2 id="having-multiple-xctestcase">Having multiple XCTestCase</h2>
<p>Previously, I told you that you can write as many test cases as you want. So if you want to run all of thems, you will have to create and run all test suites. One way to do that is to call the <code>run</code> method on each default test suite. But there is a better way:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">globalSuite</span> <span class="p">=</span> <span class="n">XCTestSuite</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="s">&#34;Global - All tests&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">addTest</span><span class="p">(</span><span class="n">HelloServiceTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">addTest</span><span class="p">(</span><span class="n">FooTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></div><p>The main advantage of creating a global test suite is to have numbers that aggregate all the cases. You will have results and failures for each test suite, and at the end, the global count.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Suite ‘Global — All tests’ passed at 2020–04–30 16:31:24.794.</p>
<p>Executed 3 tests, with 0 failures (0 unexpected) in 0.018 (0.028) seconds</p>
</div>
        </div>
    </div>
<p>Adding a suite to a suite is possible because everything is <code>XCTest</code>: <code>XCTestCase</code> and <code>XCTestSuite</code> inherit from <code>XCTest</code>. If you have multiple unit test targets in your project, you will see that your tests are grouped per class and target.</p>
<h2 id="improving-errors">Improving errors</h2>
<p>Reading errors through a long log isn’t the most attractive way to work in Test-Driven Development. There aren’t those little red or green badges next to every test. To improve our experience, we can use <code>XCTestObservationCenter</code> to observe the progression of test runs through an object implementing <code>XCTestObservation</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">TestObserver</span><span class="p">:</span> <span class="n">NSObject</span><span class="p">,</span> <span class="n">XCTestObservation</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testCase</span><span class="p">(</span><span class="kc">_</span> <span class="n">testCase</span><span class="p">:</span> <span class="n">XCTestCase</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">didFailWithDescription</span> <span class="n">description</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">inFile</span> <span class="n">filePath</span><span class="p">:</span> <span class="nb">String</span><span class="p">?,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">atLine</span> <span class="n">lineNumber</span><span class="p">:</span> <span class="nb">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Do something here.</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">testObserver</span> <span class="p">=</span> <span class="n">TestObserver</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">XCTestObservationCenter</span><span class="p">.</span><span class="n">shared</span><span class="p">.</span><span class="n">addTestObserver</span><span class="p">(</span><span class="n">testObserver</span><span class="p">)</span>
</span></span></code></pre></div><p>Multiple methods are responding to different events. The one in the example is called when a test case reports a failure. This is an opportunity to improve feedback.</p>
<p>We can add an <code>assertionFailure</code>, for example. In a playground, this statement will stop the execution. Because the log is written progressively, the last message will be our error message.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Case ‘-[HelloServiceTests testMakeMessage]’ started.</p>
<p>MyPlayground.playground:26: error: -[HelloServiceTests testMakeMessage] : XCTAssertEqual failed: (“15873012445 — Hello.”) is not equal to (“1587301244 — Hello.”)</p>
<p>Fatal error: XCTAssertEqual failed: (“15873012445 — Hello.”) is not equal to (“1587301244 — Hello.”): file MyPlayground.playground, line 26</p>
</div>
        </div>
    </div>
<p>We can also code our data structure and have a better print, or whatever other behavior we want. And why not a live view?</p>
<hr>
<h1 id="organizing-files">Organizing files</h1>
<p>As I see Playgrounds, it’s meant for easily and quickly prototype and try things. It can be difficult to make a big project with it, mainly because of the file management and the tree structure. However, we don’t have to do everything in one file.</p>
<h2 id="having-multiple-files">Having multiple files</h2>
<p>The Navigator, the left panel of Xcode and Playgrounds, is often hidden. Well, it’s understandable: we code almost all the time only in the main window and file. If you take a look at the Navigator, you can see a <code>Sources</code> folder.</p>
<p>Here, you can add every file we want. The <code>Sources</code> folder is considered as a different module by Playgrounds. It means two things. First, you need to explicitly set access levels to <code>public</code> on every object, method, or property you want to access. In a Swift module, the default access level is <code>internal</code>.</p>
<p>Second, the module is compiled when a change occurs in it, and only inside it. It’s a big gain of time. Editing code in the main file of the Playgrounds does not affect the module. It is why we can keep a really quick feedback.</p>
<hr>
<h1 id="conclusion">Conclusion</h1>
<p>It is easy to write unit tests and to run them in Playgrounds, and we are using tools that we already know. Playgrounds adds a very appreciable real-time execution for doing Test-Driven Development. The responsiveness of the feedback is really great, it’s a big advantage for the red-green-refactor cycle.</p>
<p>This is not perfect for handling multiple files of a big project, or displaying errors, but we have solutions to improve our experience. It’s not a big problem to work, to prototype, to explore.</p>
<p>In future articles, I will tell you about other ways to speed-up Test-Driven Development in Swift. We will see how we can use Swift Package or frameworks to help us. Keep in touch :)</p>
]]></description></item><item><title>FIRST : 5 principes pour guider l’écriture des tests unitaires</title><link>https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/</link><pubDate>Mon, 20 Apr 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/</guid><description><![CDATA[<p>Écrire du code propre est essentiel, et écrire des tests propres l’est tout autant, si ce n’est plus. Design émergent, aide pour retranscrire le métier, documentation, maintenabilité et évolution du code, les tests jouent de multiples rôles au sein d’un projet. C’est pourquoi il est important d’avoir des tests de qualité.</p>
<p>Dans cet article, je vous propose d’explorer 5 principes qui pourront vous guider et vous challenger pour l’écriture de vos tests unitaires. Ces principes sont connus sous l’acronyme FIRST, signifiant avoir des tests :</p>
<ul>
<li>Fast 🚅</li>
<li>Independent 📦</li>
<li>Repeatable ♻️</li>
<li>Self-validating ✅</li>
<li>Timely ⏱</li>
</ul>
<p>En s’inspirant de ces bonnes pratiques, la qualité de vos tests s’améliorera et la qualité du projet et du code de production suivra. Pour mieux comprendre ces principes, faisons le tour de chacun d’eux en explorant leurs raisons d’être, les possibles problèmes en cause et des pistes de solutions.</p>
<figure>
</figure>

<hr>
<h1 id="f--fast-">F : Fast 🚅</h1>
<p>Exécuter un test doit être rapide, et surtout, lancer l’ensemble des tests doit être rapide. Cela inclut le temps des <em>setup</em> et <em>teardown</em>, et même de la compilation. Un test unitaire rapide mais avec une longue compilation ou un long setup est un test long. <strong>Si vous hésitez pour lancer vos tests après une modification, c’est que vos tests sont probablement trop longs</strong>.</p>
<p>Lorsque les tests sont longs, les workflow de développement et de déploiement sont ralentis. Par ailleurs, un des bénéfices des tests unitaires est d’obtenir un feedback rapide. Pour conserver cet aspect, il faut que les tests soient rapides.</p>
<p>C’est encore plus important lorsque vous utilisez un outil qui exécute automatiquement les tests unitaires impactés par vos modifications. C’est le cas en C# par exemple, avec Visual Studio et le <a href="https://docs.microsoft.com/fr-fr/visualstudio/test/live-unit-testing?view=vs-2019" target="_blank" rel="noopener noreffer">Live Unit Testing</a>.</p>
<p>Mais alors, qu’est-ce qu’un test long ? Prenons 150ms. Ça n’a l’air de rien, mais si chaque test prend 150ms, le cumul peut devenir bien plus long. Sur un projet ayant 2000 tests, et cela peut vite augmenter si l’équipe en ajoute régulièrement, on arrive à un total de 5 minutes ! Cumulé sur une journée, c’est énorme et c’est sans compter le temps de compilation ou de setup.</p>
<p>Un temps aussi grand va créer un point de douleur qui va démotiver le développeur, ce qui aura pour conséquence de diminuer la fréquence à laquelle il lance les tests. Dans le pire des cas, il pourrait même ne plus du tout lancer les tests.</p>
<p>Pour avoir un feedback rapide, il est nécessaire de lancer très souvent les tests pendant que l’on développe. En perdant le feedback rapide, on perd aussi du temps. On obtient bien plus tard l’information que quelque chose a cassé. De nombreuses modifications ont pu être ajoutées et il faut identifier laquelle est responsable de l’erreur.</p>
<h2 id="causes">Causes</h2>
<p>Les dépendances lourdes comme les accès à une base de données, les appels réseaux, ou les lectures de fichiers sont souvent les responsables d’un test long. Ces opérations durent des centaines de millisecondes, voire plusieurs secondes.</p>
<p>Parfois, les traitements asynchrones ralentissent les tests par le traitement lourd qu’ils peuvent faire, et possiblement aussi par la manière dont les tests gèrent l’asynchronisme (le test étant bloqué tant qu’une réponse n’est pas arrivée). Le multithreading peut poser le même problème.</p>
<h2 id="solutions">Solutions</h2>
<p>L’injection de dépendance, ou le principe d’inversion de contrôle, est un moyen efficace de s’abstraire des dépendances. Les implémentations réelles sont remplacées par des simulacres, comme des <a href="https://martinfowler.com/bliki/TestDouble.html" target="_blank" rel="noopener noreffer">Test Double</a>, qui permettent de simuler des comportements.</p>
<p>En créant une classe qui agira à la place d’un service effectuant une requête HTTP, par exemple, on obtient la flexibilité d’avoir la valeur que l’on souhaite immédiatement. Retourner des objets prédéfinis dans une fonction est une instruction instantanée contrairement à un appel réseau.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">TimeoutArticlesProvider</span><span class="p">:</span> <span class="n">ArticlesProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">fetchAllArticles</span><span class="p">(</span><span class="n">completion</span><span class="p">:</span> <span class="p">((</span><span class="n">Result</span><span class="p">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="n">ApiError</span><span class="p">&gt;)</span> <span class="p">-&gt;</span> <span class="nb">Void</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">completion</span><span class="p">(.</span><span class="n">failure</span><span class="p">(.</span><span class="n">timeout</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h1 id="i--independent-">I : Independent 📦</h1>
<p>Un test ne doit pas dépendre d’un autre test. Le résultat d’un test ne doit pas non plus affecter un autre test. Cela peut causer des faux positifs ou cacher un problème. On perdrait du temps à parcourir plusieurs tests pour découvrir l’origine d’une erreur.</p>
<p>On devrait pouvoir lancer les tests dans n’importe quel ordre. De même, on devrait pouvoir lancer n’importe quel sous-ensemble de tests : un seul, une suite de plusieurs tests, ou tous. Si ce n’est pas le cas, c’est une indication que certains tests dépendent les uns des autres.</p>
<p>Tendre vers des tests indépendants permet de focaliser chaque test sur un comportement précis, ce qui donne davantage de sens au mot <em>unitaire</em>. <strong>Un test ne devrait avoir qu’une seule raison d’échouer</strong>. Cela permet d’identifier rapidement la cause d’une erreur, on comprend tout de suite pourquoi le test a échoué. On évite ainsi une longue session de debug.</p>
<p>On veut donc se rendre indépendant d&rsquo;une base de données par exemple, pour éviter que l&rsquo;écriture dans un test A affecte le résultat d&rsquo;un test B. Ce peut être la même chose pour des singletons, des fichiers. Eventuellement, on va vouloir devenir indépendant de choses lourdes comme les appels réseaux, notamment pour respecter les principes <em>Fast</em> et <em>Repeatable</em>.</p>
<p>Attention à ne pas tomber dans l&rsquo;extrême. On ne veut pas que le SUT (System Under Test) soit isolé de tout. Non. On veut seulement rendre le test indépendant. Le SUT peut être une classe comme un ensemble de classes, un module. Tout mocker posera des problèmes et rendra le test fragile.</p>
<h2 id="causes-1">Causes</h2>
<p>Compter sur un enchaînement de plusieurs tests afin d’effectuer des actions prérequises à l’exécution d’un autre test va créer un lien de dépendance. De même que partager un état avec d’autres tests. On peut par exemple retrouver ces états dans des propriétés de la classe de test, dans des singletons, dans des bases de données, dans la lecture et l&rsquo;écriture de fichiers&hellip; Bref, tout ce qui est partagé.</p>
<h2 id="solutions-1">Solutions</h2>
<p>Ici aussi l&rsquo;injection de dépendance aidera à remplacer les dépendances gênantes pour le test. A celà, on peut ajouter le modèle <strong>Arrange-Act-Assert</strong> afin de structurer l’écriture d’un test en trois grandes parties en plus d’apporter de la rigueur et de la cohérence entre les tests.</p>
<ul>
<li><em>Arrange</em> : on prépare toutes les données requises pour le test, ainsi que l’état dans lequel le test doit se trouver. On s’abstrait des autres tests et de l’environnement, ainsi que des dépendances en créant les <a href="https://martinfowler.com/bliki/TestDouble.html" target="_blank" rel="noopener noreffer">Test Double</a> nécessaires.</li>
<li><em>Act</em> : la méthode testée est appelée. Les données requises ont été initialisées dans l’étape précédente, et les dépendances injectées.</li>
<li><em>Assert</em> : on vérifie que le résultat est bien celui qu’on attend grâce aux différentes méthodes <em>Assert</em> du framework de test. Un test doit tendre à n’avoir qu’un seul assert pour n’avoir qu’une seule raison d’échouer. Dans certains cas, on peut avoir plusieurs assert lorsqu’ils se regroupent sous une même logique.</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloServiceTests</span><span class="p">:</span> <span class="n">XCTestCase</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testMakeMessage</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Arrange</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="mi">1587301244</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">dateProvider</span> <span class="p">=</span> <span class="n">FakeDateProvider</span><span class="p">(</span><span class="n">now</span><span class="p">:</span> <span class="n">now</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">service</span> <span class="p">=</span> <span class="n">HelloService</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">dateProvider</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Act</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">message</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">makeMessage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Assert</span>
</span></span><span class="line"><span class="cl">        <span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s">&#34;1587301244 - Hello.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Un autre moyen de donner de l’indépendance aux tests est d’utiliser les méthodes de <em>setup</em> et de <em>teardown</em>. Ces méthodes sont respectivement appelées avant et après l’exécution de chaque test. Le teardown est très utile pour effectuer un nettoyage après chaque test, par exemple.</p>
<p>Le nommage des tests a son importance et peut aider à rendre des tests indépendants. Chercher à mettre en valeur l’intention du test à travers son nom force à tester un comportement plus précis. Et par la même occasion, cela facilite la compréhension pour déterminer pourquoi le test a échoué.</p>
<p>Certains frameworks ou IDEs proposent d’exécuter les tests dans un ordre aléatoire. Activez cette option. Vous aurez rapidement une idée quels tests ont un problème, et cela vous empêchera peut-être d&rsquo;ajouter un nouveau test dépendant.</p>
<hr>
<h1 id="r--repeatable-">R : Repeatable ♻️</h1>
<p>Un test doit toujours produire le même résultat. Toujours. Peu importe le nombre de fois où il est exécuté, la date ou le lieu. Si un test ne réagit parfois pas de la même manière, on ne peut pas lui faire confiance.</p>
<p>Comment savoir si la raison d’un échec est “normale” ou réellement problématique ? À quel point les erreurs sont bien détectées ? <strong>En se posant sans cesse des questions sur les tests, on perd en sérénité</strong>, rendant alors les changements dans le code plus difficiles et plus hésitants.</p>
<p>Pour un état de départ donné et une action exécutée, on doit pouvoir prédire la réponse. Sans résultat déterministe, les sessions de debug seront plus compliquées lorsque des erreurs surviendront (et idéalement, on n&rsquo;a pas besoin de debugguer). Certains problèmes pourraient être difficiles, voire impossibles à reproduire à l’identique.</p>
<p>Un test doit éviter de dépendre de sources de données non-prévisibles. Des sources changeantes, pouvant être indisponibles, des états extérieurs ou des environnements sont des dépendances empêchant d’obtenir continuellement le même résultat.</p>
<h2 id="causes-2">Causes</h2>
<p>Les bases de données sont des sources de données changeantes. Elles pourraient être modifiées par d’autres tests ou d’autres lancements. Les APIs web peuvent également exposer des données différentes à chaque appel, en plus d’être potentiellement indisponible (serveur en maintenance) ou inaccessible (panne de réseau).</p>
<p>Tester du code utilisant ces types de dépendances donnera un résultat incertain. Les singletons, les configurations et les environnements peuvent aussi être responsables d’un test ayant une sortie non garantie. Plus souvent oubliés : l’utilisation des dates et des fonctions aléatoires.</p>
<h2 id="solutions-2">Solutions</h2>
<p>On veut toujours avoir le même résultat, donc on veut contrôler entièrement le test, donc on doit rendre contrôlable certaines dépendances. L’injection de dépendance permettra de s’abstraire des sources de données non-prévisibles en ayant le contrôle sur les réponses générées. Par exemple, on peut simuler une requête échouant suite à un timeout pour les besoins d’un test, et par ailleurs simuler un succès pour un autre test.</p>
<p>Cette même solution peut être utilisée pour gérer les dates et les fonctions aléatoires. Pour cela, on transforme l’accès à la date en le rendant indirect, via une interface, afin d’ajouter une abstraction qui permettra de remplacer la valeur réelle par un Test Double dans les tests.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">protocol</span> <span class="nc">DateProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">now</span><span class="p">:</span> <span class="n">Date</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">DeviceDateProvider</span><span class="p">:</span> <span class="n">DateProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">now</span><span class="p">:</span> <span class="n">Date</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Date</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloService</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kd">let</span> <span class="nv">dateProvider</span><span class="p">:</span> <span class="n">DateProvider</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">init</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">DateProvider</span> <span class="p">=</span> <span class="n">DeviceDateProvider</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">self</span><span class="p">.</span><span class="n">dateProvider</span> <span class="p">=</span> <span class="n">dateProvider</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">makeMessage</span><span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="nb">Int</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">.</span><span class="n">now</span><span class="p">.</span><span class="n">timeIntervalSince1970</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s">&#34;</span><span class="si">\(</span><span class="n">now</span><span class="si">)</span><span class="s"> - Hello.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>En complément, le modèle <em>Arrange-Act-Assert</em> apporte la structure pour définir la valeur des Test Double et l’état initial. On peut aussi s’appuyer sur les méthodes de <em>teardown</em> pour faire un nettoyage après chaque test.</p>
<hr>
<h1 id="s--self-validating-">S : Self-validating ✅</h1>
<p>Chaque test doit être autonome pour déterminer si le résultat correspond aux attentes. <strong>Personne ne devrait intervenir.</strong> Sa sortie est simple : un test a réussi ou a échoué.</p>
<p>Il ne devrait pas y avoir besoin d’interprétation manuelle. Si on est amené à lire un fichier, à comparer des résultats, à chercher des informations, il y a un risque de faire une erreur humaine. C’est aussi plus long et rébarbatif, ce qui pourrait décourager les développeurs de lancer les tests.</p>
<p>Un test ne devrait pas non plus nécessiter d’action manuelle, ni avant le lancement, ni après. Il ne faut pas avoir à intervenir pour préparer un environnement ou nettoyer des artefacts, par exemple. Si un tel besoin est présent, il faut l’automatiser ou l’intégrer dans le test.</p>
<h2 id="solutions-3">Solutions</h2>
<p>Avec les outils actuels, les tests respectent globalement déjà ce principe. Il suffit d&rsquo;ajouter une assertion dans un test pour qu&rsquo;il puisse valider lui-même le résultat ; le framework et l&rsquo;outillage s&rsquo;occupe du reste. L’assertion la plus basique est une déclaration indiquant que quelque chose doit être vrai.</p>
<p>Les frameworks de tests proposent en général plusieurs méthodes d’assertion : <em>assert true</em>, <em>assert not null</em>, <em>assert equal</em>, <em>assert throw exception</em>, etc. Au moins l’une de ces instructions doit être présente dans un test.</p>
<p>L’interprétation du résultat des tests peut s’améliorer avec des solutions plus visuelles. Certains frameworks et IDE proposent des interfaces graphiques listant les tests et mettant en valeur les succès et les échecs.</p>
<p>En ce qui concerne l’automatisation pour éviter une intervention manuelle, là encore l’injection de dépendance et la structure <em>Arrange-Act-Assert</em> sont utiles. En préparant et simulant un environnement spécifique pour un test, par exemple.</p>
<hr>
<h1 id="t--timely-">T : Timely ⏱</h1>
<p>Un test doit être écrit au bon moment. Idéalement, <strong>le test est écrit juste avant le code de production qui fera réussir le test</strong>. Ce mode opératoire apporte de réels bénéfices et fait la différence. De cette manière, on avance par plus petits bouts et on se concentre sur l’essentiel. Les tests, déjà écrits, nous aident et nous guident. On voit émerger le design du code.</p>
<p>À l’opposé, écrire les tests après le code de production comporte des risques. L’ajout de tests a posteriori est plus long et plus difficile. Cela nécessite un travail supplémentaire : il faut souvent adapter le code de production qui n’est pas testable. Ce travail est parfois conséquent et coûteux. Plus on éloigne l’écriture des tests, plus ce risque sera grand.</p>
<p>Outre la difficulté, la motivation peut baisser lorsqu’il s’agit d’écrire des tests lorsque l’on a terminé. Un sentiment de culpabilité peut également naître en pensant au temps supplémentaire à passer pour ajouter des tests et adapter le code de production alors que tout est déjà prêt.</p>
<h2 id="solutions-4">Solutions</h2>
<p>Commencer par écrire un test fait partie de l&rsquo;approche Test-Driven Development (TDD). Le développement est guidé par les tests. On est guidé pour implémenter le comportement par petites étapes. Suivre cette pratique, c’est suivre un cycle précis : <em>RED, GREEN, REFACTOR</em>.</p>
<p>Pour faire simple, on écrit d’abord un test qui échoue ou ne compile pas : c’est <em>rouge</em>. On cherche ensuite à passer au <em>vert</em> en écrivant le minimum de code de production, en allant au plus simple. Puis on <em>refactorise</em>, on améliore le code de production et le code des tests. La boucle est bouclée, alors on recommence. On itère jusqu’à ce qu’on ait répondu au besoin et qu’on soit satisfait du code.</p>
]]></description></item></channel></rss>