1: pas d’ambiguïté
Que se passe-t-il si cette référence est nulle? Si ces données ne sont pas encore initialisées? Comment le code pourrait-il être cassé? … La clé est: lorsque vous écrivez un test, vous prenez la perspective de celui qui consommera votre code . Cela vous oblige à avoir une approche holistique du comportement à mettre en œuvre. De cette façon, les ambiguïtés que vous obtenez des exigences deviennent évidentes et sont immédiatement prises en compte lors de la première écriture du code.
2. Rédigez un meilleur code
En règle générale, les développeurs qui n’écrivent pas de tests voient cette pratique comme une perte de temps: en effet, pourquoi écrire le code lui-même et ensuite écrire plus de code pour revérifier la logique qui vient d’être écrite. Un test manuel rapide suffit, n’est-ce pas? Non, ça ne l’est pas. Lorsque vous écrivez des tests, vous réalisez à quel point il est difficile de faire un « one shot ». Vous apprenez à NE PAS faire confiance à votre propre code et à vous remettre en question. Notre cerveau est puissant mais est soumis à des limitations de biais cognitifs . Revérifier le code conduit nécessairement à détecter de nombreuses erreurs.
3. Un meilleur design
La plupart des jeunes développeurs adorent mettre en œuvre des design patterns. Dans le monde réel, la plupart des codes écrits dépendent d’infrastructures complexes telles que l’interface utilisateur, les bases de données, les réseaux… Une pratique essentielle promue par la POO consiste à faire abstraction des implémentations d’infrastructure complexes derrière les interfaces. En réalité, on ne peut pas faire abstraction de tout. L’une des principales difficultés consiste à identifier rapidement ce qui devrait être extrait et ce qui ne devrait pas l’être . En écrivant des tests, le code s’exerce dans un contexte de sandbox. Ecrire du code et des tests en même temps conduit à un code entièrement testable. En fin de compte, un code entièrement testable finit par être une définition de code bien conçu .
4. Débogage plus facile
Le débogage peut être une activité fastidieuse. Il faut généralement du temps pour démarrer une application entière et atteindre manuellement le bon contexte qui appellera le code à déboguer. Le débogage implique de nombreuses expériences: par conséquent, ce processus coûteux doit être répété encore et encore jusqu’à ce que le code fonctionne parfaitement.
Comme expliqué dans la section précédente, l’écriture de tests oblige le développeur à extraire le code de l’infrastructure complexe sous-jacente. De cette façon, il devient plus facile d’écrire un test dans un certain contexte et on gagne beaucoup de temps.
5. Documentation de code à jour
La rédaction et la maintenance de la documentation sont considérées comme un fardeau par les développeurs. Après tout, le code source est la conception. Si l’on veut faire du reverse-engineering sur son fonctionnement, il faut lire le code source. Mais la lecture de code est difficile et conduit à beaucoup de WTF: pourquoi est-il implémenté de cette façon? Quelle devrait être la sortie compte tenu de l’entrée? Dans quel ordre ces méthodes doivent-elles être appelées? Quelle était l’intention initiale? La documentation est donc nécessaire, mais elle est un fardeau, en particulier pour la garder synchronisée avec les modifications du code. Dans ce contexte, les tests constituent en eux-mêmes une excellente documentation:
- Les tests sont écrits au moment du développement, ils capturent l’intention initiale qui est souvent quelque peu floue par les détails d’implémentation.
- Les tests doivent nécessairement être tenus à jour avec les modifications du code. Sinon, ils ne peuvent pas passer.
- Un test est un petit programme qui exécute pas à pas un scénario.
6. Mesurer les progrès
Une mesure clé à suivre est la quantité de code réellement exercée par votre suite de tests automatiques. C’est ce qu’on appelle la couverture de code. Plus il y en a, mieux c’est. Lorsque 100% du code qui vient d’être écrit est couvert par des tests, cela signifie beaucoup de choses:
- Votre code est entièrement testable et par conséquent, il est bien conçu. Lorsque le code sera modifié, les modifications seront facilement testables sans qu’il soit nécessaire de modifier la conception.
- Votre code peut avoir quelques bogues. Mais pas pour l’ensemble d’entrées donné capturé par les tests. Cela limite beaucoup le potentiel de bogues.
- Vous avez atteint une étape importante. Souvent, lorsque 100% du code est couvert, tous les cas marginaux sont testés et aucun autre test n’est nécessaire.
J’entends souvent les développeurs affirmer qu’ils ne veulent pas perdre de temps à écrire des tests pour couvrir du code trivial comme les getters de propriété. La question est: pourquoi ces propriétés ne sont pas encore couvertes par les tests existants?
D’autres affirment qu’il faut du temps pour couvrir les 10% restants d’une classe. Cela signifie simplement qu’une telle classe n’est pas testable et donc, par définition , n’est pas bien conçue.
Un autre débat typique est que la couverture à 100% n’a pas de sens car ce qui compte vraiment, c’est ce qui est affirmé dans le code de test. Pour moi, la bonne façon de mettre en œuvre une couverture à 100% est également d’ affirmer tout ce qui peut être affirmé dans le code. De cette façon, beaucoup plus d’assertions sont contestées au moment du test. De plus, le code de test devient plus clair car il se concentre sur l’affirmation des états les plus pertinents.
En fin de compte, mesurer les progrès à travers la quantité de code automatiquement exercé par les tests gamifie le processus de développement et aide à clarifier la définition de fait .
7. Régression
Les tests manuels sont souvent considérés comme des smoke tests. Il est qualifié comme cela car l’avantage des tests manuels disparait dès qu’une seule ligne de code est modifiée dans le comportement testé.
D’un autre côté, la caractéristique clé des tests automatiques est – wait for it – être automatiquement réussis, encore et encore. Lorsqu’un changement de code provoque un échec de test, soit un bogue de régression a été introduit, soit l’exigence capturée par le test a changé. Dans le monde réel, lorsque le code est bien testé avec un taux de couverture élevé, la plupart des régressions sont en effet détectées tôt et automatiquement.
Cette discussion est liée au fait que les tests doivent être rapides à exécuter car ils sont extraits de l’infrastructure sous-jacente complexe. Voici, pour moi, la différence entre les tests unitaires et les tests d’intégration: il est normal d’avoir de longs tests qui exercent plusieurs couches de votre application à la fois. Mais vous devez garder à l’esprit qu’ils ne seront pas exécutés aussi souvent que les tests unitaires qui devraient généralement tous être passés en quelques secondes.
8. Refactoriser en toute confiance
Ce qui différencie l’industrie du logiciel des industries comme comme celle des voitures ou les avions, c’est que les logiciels ne rouille pas avec le temps. Par exemple, vous pouvez avoir de nombreux composants intacts depuis plus d’une décennie qui fonctionnent toujours parfaitement.
Les logiciels ne rouillent pas avec le temps, mais les exigences évoluent avec le temps. Les utilisateurs de logiciels veulent constamment plus de fonctionnalités avec moins de performances consommées. De plus, le contexte sous-jacent change souvent: le code .NET qui fonctionne correctement sous Windows doit maintenant fonctionner également sous Linux et MacOS. Il s’agit de la maintenabilité du logiciel.
Une conséquence de la maintenabilité est la nécessité de refactoriser: restructurer le code de travail pour pouvoir gérer de nouvelles exigences. Mais une difficulté majeure est de restructurer le code de travail sans casser toutes les exigences passées auxquelles il répond. Lorsqu’il n’y a pas de tests, il n’est pas rare de voir des classes et des méthodes complexes intactes pendant des années car personne dans l’équipe ne sait vraiment comment cela fonctionne. Mais comme aucun utilisateur ne se plaint, nous savons que cela fonctionne. Et malgré les nouvelles exigences, personne ne prend le risque de le refactoriser et de le casser!
D’un autre côté, si vous avez une suite de tests décente, la plupart des exigences passées s’exercent automatiquement: les tests sont un filet de sécurité pour la refactorisation . Quelle que soit l’ampleur de l’impact de la refactorisation nécessaire, avec une suite de tests solide, vous pouvez refactoriser en toute confiance.
9. Créer vos releases en toute confiance
Lorsque vous commencez à comprendre comment le code nouveau et refactorisé est réellement testé, vous vous évitez beaucoup de stress et de frictions une fois le code publié. Pour cela, vous pouvez exécuter certaines règles de code sur votre code par rapport à la dernière version en production (la ligne de base). Le code de production ne sera probablement pas cassé par des modifications de code bien testées. De cette façon, vous pouvez capitaliser sur le fait que les utilisateurs sont satisfaits du code et éviter de tout re-tester manuellement.
Il n’est jamais trop tard pour prendre l’habitude d’écrire des tests .
10. Gagnez du temps et profitez-en!
Lorsque les développeurs écrivent des tests, le temps est gagné à tous les niveaux. Chaque puce précédente le démontre. Gain de temps signifie moins de frictions avec les utilisateurs et la direction car les nouvelles exigences peuvent être implémentées plus rapidement. Et avec moins de bogues de régression, moins de temps est passé à les corriger!
De plus, il est tellement plus agréable de travailler dans une base de code bien testée. Moins de régressions, moins de frictions, moins de stress, plus de communications, tout cela est des avantages d’écrire des tests. Vous êtes essentiellement un développeur parce que vous aimez automatiser les choses. En écrivant des tests, vous automatisez en fait de nombreuses tâches répétitives et fastidieuses de développement de logiciels. De cette façon, la plupart de votre temps peut être consacré à des activités enrichissantes.
N’oubliez pas: si vous avez des symptômes, testez-vous 🙂
Article adapté de l’anglais. Source: https://blog.ndepend.com/10-reasons-why-you-should-write-tests/
Photo mise en avant par Ilya Pavlov on Unsplash