Zen des tests unitaires


La capacité à écrire de bons tests unitaires est une caractéristique importante de tout développeur. Mais comment comprendre que vos tests unitaires sont corrects? Un bon test unitaire est comme un bon jeu d'échecs. Dans notre cas, les échecs sont les approches que nous allons discuter dans ce post. Il n'y a pas de meilleur joueur d'échecs dans une partie d'échecs car tout dépend des positions (et d'un joueur) . De même, dans les tests unitaires, vous n'avez pas à distinguer une seule approche. En d'autres termes, vous devez utiliser toutes les approches ensemble pour obtenir le meilleur résultat. Donc, si vous voulez gagner ce jeu, alors bienvenue sous la coupe.


Débuts


Pourquoi devrais-je écrire des tests unitaires?


Vous n'êtes pas obligé d'écrire des tests unitaires à moins que vous ne soyez une personne à perception extrasensorielle qui puisse écrire du code sans bogues, que vous ayez une super mémoire, que vous puissiez compiler votre code dans votre tête ou que vous aimez la douleur. Sinon, vous devez absolument écrire des tests unitaires, car ils diminuent le nombre de bogues dans les fonctionnalités nouvelles et existantes, réduisent le coût et la peur de changer vos fonctionnalités et permettent de refactoriser votre code. De plus, vous devez toujours exécuter les tests existants et je vous recommande de faire attention aux outils de test continu.


Que tester?


De toute évidence, dans le test unitaire, vous testez le comportement d'une unité distincte (pas des invocations, car elles peuvent être modifiées ultérieurement) . Aussi, faites-en une règle pour couvrir avec des tests unitaires tous les bogues que vous avez trouvés pour prouver qu'ils sont corrigés. Qu'en est-il de la couverture du code? La couverture du code n'est pas un objectif, c'est juste une mesure qui vous aide à comprendre quelle partie de la logique vous avez oublié de couvrir avec des tests unitaires. Ce serait une énorme erreur lorsque vous décidez de couvrir chaque ligne de code avec des tests unitaires.


Mittelspiel


Testez une seule chose


Ne confondez pas les tests unitaires avec les tests d' intégration où tester plus d'une chose est normal. L'idée des tests unitaires est de prouver qu'un module d'application séparé fonctionne ou non. Vous devez comprendre facilement et certainement quel comportement dans votre code échoue et comment le corriger. Combien d'assertions devez-vous utiliser? Un! L'utilisation de nombreuses assertions peut être l'odeur de code que vous testez plus d'une chose. De plus, il est possible que quelqu'un ajoute une nouvelle assertion à votre test au lieu d'en écrire une autre. Et comment pouvez-vous comprendre comment vos autres assertions se sont terminées lorsque la première a échoué?


Évitez la logique


Les bogues dans les tests sont les choses les plus difficiles à trouver pour les développeurs. Les chances d'obtenir un bogue dans votre code de test augmentent à mesure que vous décidez d'ajouter de la logique à votre test. Il devient plus difficile à lire, à comprendre et à maintenir. L'utilisation de for , foreach , if , switch et d'autres opérateurs dans un test peut également être une odeur de code que vous testez plus d'une chose.


AAA


Arrange, Act, Assert est un modèle couramment utilisé qui aide à organiser votre code de test en trois phases en conséquence. Il sépare clairement ce qui est testé des étapes de configuration et de vérification. C'est l'une des meilleures pratiques et cela rend votre code de test plus lisible et plus facile à gérer. Cela dit, n'utilisez pas les commentaires AAA dans vos tests si vous voulez garder votre code propre et lisible. Le test créé avec compétence exprime l'idée AAA même sans commentaires.


Respectez la convention de dénomination


Les noms des tests doivent être descriptifs et compréhensibles non seulement pour leur auteur. Il existe de nombreuses stratégies de nommage de test, mais j'aime celle de Roy Osherove : [MethodName_StateUnderTest_ExpectedBehavior] . Il contient toutes les informations nécessaires sur le test de manière formatée. Il est facile de suivre cette stratégie pour tout développeur.


Exemples:


 public void Sum_NegativeNumberAs2ndParam_ExceptionThrown () public void Sum_simpleValues_Calculated () public void Parse_OnEmptyString_ExceptionThrown() public void Parse_SingleToken_ReturnsEqualTokenValue () 

Mais faites attention à ce que vous ayez une convention de dénomination que vous devrez suivre sur votre projet actuel. Ne les mélange pas.


Préparation des données de test


La construction de données de test peut apporter désordre et souffrance dans votre code de test. Vous pouvez faire face à cette situation lorsque:


  • vous devez changer le constructeur de votre modèle dans chaque morceau de code où ce modèle est créé (cela se produit généralement lorsque votre modèle est immuable) ;
  • vous avez beaucoup de doublons de code lors de la construction de vos données de test;
  • vous devez passer beaucoup de "données magiques" dans votre constructeur de modèle (par exemple, un new Device("Stub", 10, true, "http"); ) ;
  • vous avez le sentiment que vous devez créer une sorte de générateur de données aléatoires;
  • il vous est difficile de créer des collections de données de tests.

Dans cet esprit, vous devez considérer quelques alternatives courantes: mère d'objet et [modèle de générateur Fluent]. Ces approches sont également de bons joueurs d'équipe, vous pouvez donc les utiliser ensemble.


N'utilisez pas de données aléatoires, car votre test peut être sensible à certains types de valeurs. En conséquence, vous pouvez obtenir un heisenbug maléfique dans votre test, qui est difficile à trouver et à reproduire.


Apprenez votre cadre de test


Découvrez tous les attributs, assertions et autres fonctionnalités de votre framework de test. Il vous aide à rendre vos tests plus lisibles et élégants. Par exemple, dans le framework NUnit , vous pouvez utiliser deux modèles d'assertions et vous pouvez en choisir un qui vous plaît le plus:


 Assert.AreEqual(StatusCode.OK, response.StatusCode); 

ou


 Assert.That(StatusCode.OK, Is.EqualTo(response.StatusCode)); 

N'oubliez pas les méthodes de configuration et de démontage, les attributs TestCase et Category, les assertions de collection. Ne confondez pas les paramètres de résultats attendus et réels dans les assertions.


Endspiel


Votre code de test a le même privilège que votre code de production que vous devez écrire et maintenir, n'oubliez pas les principes SOLID. De plus, vos tests unitaires doivent être lisibles et il y a plusieurs raisons à cela. Premièrement, l'intention de vos tests doit être compréhensible et claire. Cela signifie que vous n'avez pas à perdre votre temps en lisant vos tests. Deuxièmement, il devrait être facile de maintenir vos tests, de détecter et d'éliminer les problèmes sans débogage.


Les tests unitaires sont une énorme philosophie qui ne peut être discutée dans un seul article. Ici, j'ai expliqué les approches courantes et les questions fréquentes liées aux tests unitaires. Si vous souhaitez approfondir, vous trouverez peut-être ces liens intéressants:


Blogue de Roy Osherove
Livre de Roy Osherove, "L'art des tests unitaires"


Restez calme et test unitaire

Source: https://habr.com/ru/post/fr439804/


All Articles