unit-testing
Les règles générales pour les tests unitaires pour toutes les langues
Recherche…
Introduction
Lorsque vous commencez avec les tests unitaires, toutes sortes de questions se posent:
Qu'est-ce qu'un test unitaire? Qu'est-ce qu'un SetUp et TearDown? Comment gérer les dépendances? Pourquoi faire des tests unitaires? Comment puis-je faire de bons tests unitaires?
Cet article répondra à toutes ces questions afin que vous puissiez commencer les tests unitaires dans la langue de votre choix.
Remarques
Qu'est-ce que le test unitaire?
Le test d'unité consiste à tester le code pour s'assurer qu'il exécute la tâche qu'il est censé effectuer. Il teste le code au niveau le plus bas possible - les méthodes individuelles de vos classes.
Qu'est-ce qu'une unité?
Tout module de code discret pouvant être testé isolément. La plupart des classes de temps et leurs méthodes. Cette classe est généralement appelée "Class Under Test" (CUT) ou "System Under Test" (SUT).
La différence entre les tests unitaires et les tests d'intégration
Les tests unitaires consistent à tester une classe unique de manière totalement indépendante de ses dépendances. Les tests d'intégration consistent à tester une classe unique avec une ou plusieurs de ses dépendances réelles.
The SetUp et TearDown
Lorsqu'elle est créée, la méthode SetUp est exécutée avant chaque test unitaire et le TearDown après chaque test.
En général, vous ajoutez toutes les étapes préalables du SetUp et toutes les étapes de nettoyage du TearDown. Mais vous ne faites ces méthodes que si ces étapes sont nécessaires pour chaque test. Si ce n'est pas le cas, ces étapes sont prises dans les tests spécifiques de la section "Arranger".
Comment gérer les dépendances
Plusieurs fois, une classe a la dépendance des autres classes pour exécuter ses méthodes. Pour pouvoir ne pas dépendre de ces autres classes, il faut faire semblant. Vous pouvez créer ces classes vous-même ou utiliser un framework d'isolement ou de maquette. Un cadre d'isolation est un ensemble de codes permettant de créer facilement de fausses classes.
Faux cours
Toute classe fournissant des fonctionnalités suffisantes pour prétendre qu'il s'agit d'une dépendance requise par une découpe. Il existe deux types de contrefaçons: les talons et les mocks.
- Un talon: Un faux qui n'a aucun effet sur la réussite ou l'échec du test et qui existe uniquement pour permettre l'exécution du test.
- Un simulacre: Un faux qui garde la trace du comportement de la CUT et réussit ou échoue au test en fonction de ce comportement.
Pourquoi les tests unitaires?
1. Les tests unitaires trouveront des bugs
Lorsque vous écrivez une suite complète de tests définissant le comportement attendu pour une classe donnée, tout ce qui ne se comporte pas comme prévu est révélé.
2. Les tests unitaires éloigneront les bogues
Faites un changement qui introduit un bogue et vos tests peuvent le révéler la prochaine fois que vous exécuterez vos tests.
3. Les tests unitaires permettent de gagner du temps
L'écriture de tests unitaires permet de s'assurer que votre code fonctionne comme prévu dès le départ. Les tests unitaires définissent ce que votre code doit faire et vous ne passerez donc pas de temps à écrire du code qui fait des choses qu'il ne devrait pas faire. Personne ne vérifie que le code ne fonctionne pas et que vous devez faire quelque chose pour vous faire croire que cela fonctionne. Passez ce temps à écrire des tests unitaires.
4. Les tests unitaires donnent la tranquillité d'esprit
Vous pouvez exécuter tous ces tests et savoir que votre code fonctionne comme il se doit. Connaître l'état de votre code, son fonctionnement, sa mise à jour et son amélioration sans crainte est une très bonne chose.
5. Les tests unitaires documentent l'utilisation correcte d'une classe
Les tests unitaires deviennent des exemples simples du fonctionnement de votre code, de ce qu'il est censé faire et de la manière correcte d'utiliser votre code en cours de test.
Règles générales pour les tests unitaires
1. Pour la structure d'un test unitaire, suivez la règle AAA
Organiser:
Mettre en place la chose à tester. Comme les variables, les champs et les propriétés pour permettre l'exécution du test ainsi que le résultat attendu.
Act: Appelez la méthode que vous testez
Affirmer:
Appelez le framework de test pour vérifier que le résultat de votre "acte" est ce qui était attendu.
2. Tester une chose à la fois isolément
Toutes les classes doivent être testées isolément. Ils ne devraient dépendre que des moqueries et des talons. Ils ne devraient pas dépendre des résultats d'autres tests.
3. Ecrivez d'abord les tests simples "au centre"
Les premiers tests que vous écrivez devraient être les tests les plus simples. Ils devraient être ceux qui illustrent les fonctionnalités que vous essayez d'écrire. Ensuite, une fois ces tests réussis, vous devez écrire les tests les plus compliqués qui testent les contours et les limites de votre code.
4. Rédiger des tests pour tester les contours
Une fois que les bases sont testées et que vous savez que vos fonctionnalités de base fonctionnent, vous devez tester les contours. Un bon ensemble de tests explorera les limites extérieures de ce qui pourrait arriver à une méthode donnée.
Par exemple:
- Que se passe-t-il si un débordement se produit?
- Que faire si les valeurs vont à zéro ou en dessous?
- Et s'ils vont à MaxInt ou MinInt?
- Et si vous créez un arc de 361 degrés?
- Que se passe-t-il si vous passez une chaîne vide?
- Que se passe-t-il si une chaîne mesure 2 Go?
5. Test à travers les frontières
Les tests unitaires doivent tester les deux côtés d'une limite donnée. Se déplacer au-delà des frontières sont des endroits où votre code peut échouer ou fonctionner de manière imprévisible.
6. Si vous le pouvez, testez l’ensemble du spectre
Si c'est pratique, testez l'ensemble des possibilités de votre fonctionnalité. S'il implique un type énuméré, testez la fonctionnalité avec chacun des éléments de l'énumération. Il peut être peu pratique de tester toutes les possibilités, mais si vous pouvez tester chaque possibilité, faites-le.
7. Si possible, couvrir tous les chemins de code
Celui-ci est également difficile, mais si votre code est conçu pour des tests et que vous utilisez un outil de couverture de code, vous pouvez vous assurer que chaque ligne de votre code est couverte par des tests unitaires au moins une fois. Couvrir chaque chemin de code ne garantit pas qu'il n'y a pas de bogues, mais cela vous donne sûrement des informations précieuses sur l'état de chaque ligne de code.
8. Ecrivez des tests qui révèlent un bogue, puis corrigez-le
Si vous trouvez un bug, écrivez un test qui le révèle. Ensuite, vous corrigez facilement le bogue en déboguant le test. Ensuite, vous avez un bon test de régression pour vous assurer que si le bogue revient pour une raison quelconque, vous le saurez immédiatement. Il est très facile de corriger un bogue lorsque vous avez un test simple et direct à exécuter dans le débogueur.
Un avantage secondaire est que vous avez testé votre test. Comme vous avez vu le test échouer et que vous l'avez vu passer, vous savez que le test est valide car il a été prouvé qu'il fonctionne correctement. Cela en fait un test de régression encore meilleur.
9. Faites chaque test indépendamment l'un de l'autre
Les tests ne doivent jamais dépendre les uns des autres. Si vos tests doivent être exécutés dans un certain ordre, vous devez modifier les tests.
10. Ecrivez un assert par test
Vous devriez écrire un assert par test. Si vous ne pouvez pas faire cela, réfractez votre code afin que vos événements SetUp et TearDown soient utilisés pour créer correctement l'environnement afin que chaque test puisse être exécuté individuellement.
11. Nommez clairement vos tests. N'ayez pas peur des noms longs
Puisque vous faites une affirmation par test, chaque test peut être très spécifique. Ainsi, n'ayez pas peur d'utiliser des noms de test longs et complets.
Un nom long et complet vous permet de savoir immédiatement quel test a échoué et exactement ce que le test essayait de faire.
Des tests longs et clairement nommés peuvent également documenter vos tests. Un test nommé "DividedByZeroShouldThrowException" documente exactement ce que fait le code lorsque vous essayez de diviser par zéro.
12. Tester que chaque exception soulevée est effectivement soulevée
Si votre code déclenche une exception, écrivez un test pour vous assurer que toutes les exceptions que vous avez générées sont déclenchées.
13. Évitez d'utiliser CheckTrue ou Assert.IsTrue
Évitez de vérifier une condition booléenne. Par exemple, si vous vérifiez si deux choses sont égales avec CheckTrue ou Assert.IsTrue, utilisez plutôt CheckEquals ou Assert.IsEqual. Pourquoi? À cause de ce:
CheckTrue (Attendu, Réel) Cela rapportera quelque chose comme: "Un test a échoué: le résultat attendu était Vrai mais le résultat réel était Faux."
Cela ne vous dit rien.
CheckEquals (Attendu, Réel)
Cela vous dira quelque chose comme: "Certains tests ont échoué: 7 attendus mais le résultat réel était 3."
Utilisez uniquement CheckTrue ou Assert.IsTrue lorsque votre valeur attendue est en réalité une condition booléenne.
14. Exécutez constamment vos tests
Exécutez vos tests pendant que vous écrivez du code. Vos tests doivent être rapides, ce qui vous permet de les exécuter même après des modifications mineures. Si vous ne pouvez pas exécuter vos tests dans le cadre de votre processus de développement normal, quelque chose ne va pas. Les tests unitaires sont supposés fonctionner presque instantanément. Si ce n'est pas le cas, c'est probablement parce que vous ne les exécutez pas isolément.
15. Exécutez vos tests dans le cadre de chaque génération automatisée
Tout comme vous devriez effectuer des tests pendant votre développement, ils devraient également faire partie intégrante de votre processus d'intégration continue. Un test échoué devrait signifier que votre build est cassé. Ne laissez pas les tests échoués s'attarder. Considérez cela comme un échec de construction et corrigez-le immédiatement.
Exemple de test unitaire simple en C #
Pour cet exemple, nous allons tester la méthode de somme d'une calculatrice simple.
Dans cet exemple, nous allons tester l'application: ApplicationToTest. Celui-ci a une classe appelée Calc. Cette classe a une méthode Sum ().
La méthode Sum () ressemble à ceci:
public void Sum(int a, int b)
{
return a + b;
}
Le test d'unité pour tester cette méthode ressemble à ceci:
[Testclass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
//Arrange
ApplicationToTest.Calc ClassCalc = new ApplicationToTest.Calc();
int expectedResult = 5;
//Act
int result = ClassCalc.Sum(2,3);
//Assert
Assert.AreEqual(expectedResult, result);
}
}