Question Pourquoi devrais-je à la fois tester l’unité ET le test Web (au lieu de simplement tester Web)?


Ma position actuelle est la suivante: si je teste en profondeur mes applications ASP.NET en utilisant des tests Web (dans mon cas via les outils de test VS.NET'08 et WatiN, peut-être) avec une couverture de code et un large spectre de données, besoin d'écrire des tests unitaires individuels, car mon code sera testé avec l'interface utilisateur à travers toutes les couches. La couverture du code garantira que je frappe chaque morceau de code fonctionnel (ou révèle un code inutilisé) et je peux fournir des données qui couvriront toutes les conditions raisonnablement prévisibles.

Cependant, si vous avez un avis différent, j'aimerais savoir:

  1. Quelle Additionnel Avantages Les tests unitaires justifient-ils l'effort d'inclusion dans un projet (gardez à l'esprit que je fais les tests Web de toute façon, donc dans de nombreux cas, les tests unitaires couvriraient le code déjà couvert par les tests Web).

  2. Pouvez-vous expliquer vos raisons en détail avec des exemples concrets? Trop souvent, je vois des réponses comme «ce à quoi cela signifie» ou «cela promeut une qualité supérieure» - ce qui ne règle pas vraiment la question pratique à laquelle je dois faire face: comment justifier, avec des résultats tangibles, plus de dépenses? test de temps?


16
2017-10-06 21:28


origine


Réponses:


La couverture du code assurera que je suis frappe chaque morceau de code fonctionnel

"Frappé" ne fait pas signifie "test"

Le seul problème avec les tests Web est qu’il ne garantit que frappé le code, et qu'il apparaît être correct à un niveau élevé.

Ce n'est pas parce que vous avez chargé la page et que celle-ci ne s'est pas arrêtée qu'elle fonctionne correctement. Voici quelques points que j'ai rencontrés où les «tests Web» couvraient 100% du code, mais manquaient complètement certains bogues très graves que les tests unitaires n'auraient pas.

  1. La page chargée correctement à partir d'un cache, mais la base de données réelle a été cassée
  2. La page a chargé chaque élément de la base de données, mais n'a affiché que le premier - il semblait bien fonctionner même si la production avait échoué complètement car cela prenait trop de temps
  3. La page affiche un numéro d'apparence valide, ce qui est en fait faux, mais il n'a pas été détecté car 1000000 est facile à prendre pour 100000
  4. La page affichée un nombre valide par coïncidence - 10x50 est le même que 25x20, mais on est FAUX
  5. La page était censée ajouter une entrée de journal à la base de données, mais celle-ci n'est pas visible pour l'utilisateur.
  6. L'authentification a été contournée pour que les tests Web fonctionnent, nous avons donc raté un bogue flagrant dans le code d'authentification.

Il est facile de trouver des centaines d'autres exemples de ce genre.

Vous avez besoin des deux tests unitaires pour vous assurer que votre code fait réellement ce qu'il est censé faire à un bas niveau, puis des tests fonctionnels / d'intégration (que vous appelez Web) en plus de cela, pour prouver qu'il fonctionne toutes ces petites pièces testées en unité sont enchaînées.


22
2017-10-06 21:47



Les tests unitaires seront probablement beaucoup plus rapides que les tests Web. Cela est vrai non seulement en termes de temps de développement (où vous pouvez tester une méthode plus facilement si vous pouvez l'obtenir directement que si vous devez créer une requête particulière qui va finir par y toucher plusieurs couches), mais aussi en temps d'exécution (l'exécution de milliers de requêtes en séquence prendra plus de temps que l'exécution de méthodes courtes des milliers de fois).

Les tests unitaires testeront les petites unités fonctionnelles. Ainsi, en cas d'échec, vous devriez pouvoir identifier facilement le problème.

En outre, il est beaucoup plus facile de simuler des dépendances avec des tests unitaires que lorsque vous atteignez le front-end complet - à moins que je ne manque quelque chose de vraiment cool. (Il y a quelques années, j'ai regardé comment les tests Web et les moqueries pouvaient s'intégrer, et à l'époque il n'y avait rien de approprié.)


9
2017-10-06 21:35



Les tests unitaires ne prouvent généralement pas qu’un ensemble de fonctionnalités donné fonctionne - du moins, il n’est pas censé le faire. Cela prouve que votre contrat de travail fonctionne comme prévu.

Les tests d'acceptation sont davantage orientés vers les besoins du client. Chaque exigence doit faire l'objet d'un test d'acceptation, mais il n'y a pas vraiment d'exigence entre les tests d'acceptation et les tests unitaires - ils peuvent même ne pas être dans le même cadre.

Les tests unitaires peuvent être utilisés pour générer du code, et la rapidité des tests est un facteur important. Lors du test, vous supprimez souvent des composants sur lesquels la classe testée s'appuie pour effectuer un test isolé.

L'acceptation teste le système comme vous le feriez, de l'interface graphique à la base de données. Parfois, ils prennent des heures ou des jours (ou des semaines) à courir.

Si vous commencez à y voir deux bêtes complètement différentes, vous serez un testeur beaucoup plus efficace.


5
2017-10-06 21:51



De bons démêleurs ciblés accélèrent la recherche et la résolution des problèmes lorsqu'ils surviennent. Quand un moment le plus difficile s'écrit, vous savez à peu près ce que signifie l'échec et ce qui l'a causé.

En outre, ils sont généralement plus rapides à exécuter, ce qui signifie que vous êtes beaucoup plus susceptible de les exécuter lors du développement dans le cadre de votre cycle de vérification des modifications (au lieu de le faire uniquement lorsque vous êtes sur le point de vous enregistrer).


2
2017-10-06 21:38



Lorsque vous écrivez des tests unitaires, vous serez obligé d'écrire votre code d'une meilleure manière. Plus faiblement couplé et plus orienté objet. Cela conduira à une meilleure architecture et à un système plus flexible.

Si vous écrivez des tests unitaires dans un style TDD, vous ne ferez probablement pas autant de code inutile car vous vous concentrerez sur des étapes minuscules et ne ferez que le nécessaire.

Vous serez plus en confiance lors de la refactorisation pour améliorer votre code afin d’améliorer la maintenabilité et de réduire les odeurs de code.

Et le test unitaire servira de documentation exilente sur ce que le système fait et ne fait pas.

Ce ne sont là que quelques exemples des avantages que j'ai constatés lors de l'application de TDD à mon travail.


2
2017-10-06 21:58



Un autre aspect: pardonnez l’environnement plutôt idéal dans lequel il se trouve:

Supposons que vous ayez trois composants qui doivent finalement fonctionner ensemble. Chacun peut être individuellement entièrement testé à l'unité (peu importe ce que cela signifie) avec 5 tests unitaires. Cela fait 5 + 5 + 5 = 15 tests unitaires pour une couverture complète.

Maintenant, si vous avez votre test d'intégration / Web / combiné qui teste tous les composants ensemble, vous auriez besoin (souvenez-vous du monde idéal pour ce scénario abstrait) 5 * 5 * 5 = 125 des tests qui testent toutes les permutations pour vous donner le même résultat que les 15 cas de test ci-dessus (étant donné que vous pouvez même déclencher toutes les permutations, sinon un comportement non testé / non spécifié pourrait vous affecter plus tard).

De plus, les 125 cas de test auraient une configuration beaucoup plus compliquée, un délai d'exécution plus long et une facilité de maintenance considérablement réduite en cas de modification de la fonctionnalité. Je préfère opter pour des tests de 15 unités et des tests Web de base qui garantissent que les composants sont correctement câblés.


2
2018-02-17 19:16



Les tests unitaires vous donnent la rapidité et surtout la précision du point où une défaillance ou un bogue a été introduit. Il vous permet de tester chaque composant, isolé de tous les autres composants et de vous assurer qu'il fonctionne comme il se doit.

Par exemple, si vous avez effectué un test Web, celui-ci a renvoyé une demande Ajax à un service sur le serveur qui a ensuite atteint une base de données, qui échouait alors. Était-ce le Javascript, le service, la logique métier ou la base de données à l'origine du problème?

Si, comme si vous testiez seul chacun des services, en supprimant ou en modélisant la base de données ou chaque unité de logique métier, vous êtes plus susceptible de savoir exactement où se trouve le bogue. Les tests unitaires concernent moins la couverture (bien qu'importante) et davantage l'isolement.


1
2017-10-06 21:39



Presque comme l'a dit Dijkstra: les tests unitaires ne peuvent être utilisés que pour montrer que le logiciel présente des défauts, et non pour prouver qu'il est exempt de défauts. Donc, en général, le fait d’atteindre chaque chemin de code une fois (et d’obtenir une couverture de 100%) n’a rien à voir avec les tests - cela aide simplement à éliminer le bitrot.

Si vous le jouez par le livre, chaque bogue sérieux devrait être éliminé seulement après qu'un test unitaire ait été écrit pour déclencher ce bogue. Par coïncidence, corriger le bogue signifie que ce test d'unité particulier ne tombe plus en panne. À l'avenir, ce test d'unité vérifie que ce bogue particulier reste fixe.

Il est beaucoup plus facile d’écrire un test unitaire qui déclenche un bogue particulier que d’écrire un test (Web) de bout en bout qui le fait UNIQUEMENT et n’exécute pas des tas de codes complètement inutiles en cours de route avec l'analyse des causes profondes).


1
2017-10-06 22:12



Tests unitaires que chaque composant fonctionne. Celles-ci sont extrêmement utiles pour détecter les défauts proches de leur création, ce qui réduit considérablement le coût de résolution des défauts et réduit considérablement le nombre de défauts qui se retrouvent dans votre version. De plus, de bons tests unitaires rendent la refactorisation beaucoup plus facile et plus robuste.

Les tests d'intégration (ou tests "web" dans ce cas) sont également très importants mais constituent une ligne de défense ultérieure aux tests unitaires. Un seul test d’intégration couvre un si grand nombre de codes que lorsque l’on échoue, il faut beaucoup de recherches pour déterminer le défaut (ou éventuellement le groupe de défauts) à l’origine de l’échec. Ceci est coûteux, surtout lorsque vous essayez de tester une version validée pour la faire sortir. Cela est d'autant plus coûteux que les chances d'introduire un bogue avec le correctif ont tendance à être assez élevées en moyenne et que le risque que cet échec bloque des tests supplémentaires de la version (ce qui est extrêmement coûteux pour le cycle de développement).

En revanche, lorsqu'un test unitaire échoue, vous savez exactement où se trouve le code défectueux et vous savez généralement exactement ce que le code fait mal. En outre, un échec de test unitaire ne devrait avoir d’impact qu’un seul développeur à la fois et être corrigé avant l’enregistrement du code.

Il est toujours plus coûteux de corriger les bogues plus tard que précédemment. Toujours.

Envisagez de construire une automobile. Attendriez-vous que l’ensemble du véhicule quitte la chaîne de montage pour tester le fonctionnement de chaque composant? À ce stade, si vous découvrez que le lecteur de CD ou le moteur, le climatiseur ou le régulateur de vitesse ne fonctionne pas, vous devez retirer tout le véhicule de la ligne, résoudre le problème, puis tout tester à nouveau révéler tout nouveau défaut). C'est évidemment la mauvaise façon de le faire, tout comme il est faux d’essayer de lancer un logiciel en ne testant que si cela fonctionne à la fin du processus plutôt qu’à chaque étape importante de la situation.


1
2017-10-06 22:22



Cela dépend de l'architecture de l'application ASP.NET. Si les pages Web ne font que brancher une couche logique métier ou une couche d'accès aux données sous-jacente, les tests unitaires fonctionnant indépendamment du modèle d'état ASP.NET sont plus rapides pour les développeurs et exécutés que les tests WaitiN similaires.

J'ai récemment développé une zone d'une application ASP.NET héritée, dans Visual Studio 2003, avec NUnit comme infrastructure de test. Alors qu'auparavant, les tests impliquaient de passer par des tests d’interface utilisateur pour s’assurer que les fonctionnalités étaient correctement implémentées, 90% des tests s’étaient produits sans nécessiter d’interaction avec l’interface utilisateur.

Le seul problème que j'avais était l'estimation du temps - l'une des tâches était prévue dans Trac: prendre 1 jour pour la logique d'accès aux données / métier et 2 jours pour la création et le test de l'interface utilisateur. Avec NUnit s'exécutant sur la logique d'accès aux données / métier, le temps consacré à cette partie du développement est passé de 1 jour à 2 jours. Le développement de l'interface utilisateur a été réduit à une demi-journée.

Cela a continué avec d'autres tâches dans le nouveau module étant ajouté à l'application. Les tests unitaires ont détecté les bogues plus rapidement et d'une manière moins pénible (pour moi) et j'ai davantage confiance dans l'application fonctionnant comme prévu. Mieux encore, les tests unitaires sont très reproductibles, car ils ne dépendent d'aucune nouvelle conception de l'interface utilisateur. Ils ont donc tendance à être moins fragiles, car les modifications de conception échouent lors de la compilation, pas à l'exécution.


0
2017-10-06 21:40