web-dev-qa-db-fra.com

Test unitaire Catalogue Anti-Patterns

anti-pattern: il doit y avoir au moins deux éléments clés présents pour distinguer formellement un anti-pattern réel d'un mauvais simple habitude, mauvaise pratique ou mauvaise idée:

  • Certains schémas d'action, de processus ou de structure répétés qui semblent initialement bénéfiques, mais qui produisent en fin de compte plus de mauvaises conséquences que de résultats bénéfiques, et
  • Une solution refactorisée clairement documentée, éprouvée dans la pratique et reproductible.

Votez pour l'anti-schéma TDD que vous avez vu "à l'état sauvage" une fois de trop.
Le billet de blog de James Carr et Discussion connexe sur yahoogroup testdrivendevelopment

Si vous en avez trouvé un "sans nom", postez-les aussi. Un post par anti-pattern s'il vous plaît pour que les votes comptent pour quelque chose.

Mon intérêt direct est de trouver le sous-ensemble top-n afin que je puisse en discuter dans une réunion déjeuner dans un avenir proche.

203
Gishu

Second Class Citizens - le code de test n'est pas aussi bien refactorisé que le code de production, contenant beaucoup de code dupliqué, ce qui rend difficile la maintenance des tests.

70
Ilja Preuß

Le Free Ride/Piggyback - James Carr, Tim Ottinger
Plutôt que d'écrire une nouvelle méthode de scénario de test pour tester une autre/fonctionnalité/fonctionnalité distincte , une nouvelle assertion (et ses actions correspondantes, c'est-à-dire Agir pas de AAA) monte dans un cas de test existant.

67
Gishu

Chemin heureux

Le test reste sur des chemins heureux (c'est-à-dire les résultats attendus) sans tester les limites et les exceptions.

Antipatterns JUnit

64
Geoglyph

Le héros local

Un scénario de test qui dépend de quelque chose de spécifique à l'environnement de développement sur lequel il a été écrit pour s'exécuter. Le résultat est que le test réussit sur les boîtes de développement, mais échoue lorsque quelqu'un essaie de l'exécuter ailleurs.

La dépendance cachée

Étroitement lié au héros local, un test unitaire qui nécessite que certaines données existantes aient été remplies quelque part avant l'exécution du test. Si ces données n'étaient pas renseignées, le test échouera et laissera peu d'indications au développeur sur ce qu'il voulait, ou pourquoi ... les obliger à fouiller dans des hectares de code pour savoir d'où les données qu'il utilisait étaient censées provenir.


Malheureusement, cela a été trop souvent constaté avec les anciens fichiers .dll qui dépendent de fichiers .ini nébuleux et variés qui sont constamment désynchronisés sur un système de production donné, et encore moins qui existent sur votre machine sans consultation approfondie des trois développeurs responsables de ces DLL. Soupir.

59
annakata

Chain Chain

Quelques tests qui doivent être exécutés dans un certain ordre, c'est-à-dire qu'un test modifie l'état global du système (variables globales, données dans la base de données) et le ou les tests suivants en dépendent.

Vous voyez souvent cela dans les tests de base de données. Au lieu d'effectuer une restauration dans teardown(), les tests valident leurs modifications dans la base de données. Une autre cause courante est que les modifications de l'état global ne sont pas encapsulées dans des blocs try/finally qui nettoient en cas d'échec du test.

58
Aaron Digulla

La moquerie
Parfois, la moquerie peut être bonne et pratique. Mais parfois, les développeurs peuvent se perdre et s'efforcer de se moquer de ce qui n'est pas testé. Dans ce cas, un test unitaire contient tellement de simulations, de moignons et/ou de contrefaçons que le système testé n'est même pas testé du tout, mais les données renvoyées par les simulations sont ce qui est testé.

Source: poste de James Carr.

56
Gishu

Le Silent Catcher - Kelly?
Un test qui réussit si une exception est levée .. même si l'exception qui se produit réellement est celle qui est différente de celle prévue par le développeur.
Voir aussi: Secret Catcher

[Test]
[ExpectedException(typeof(Exception))]
public void ItShouldThrowDivideByZeroException()
{
   // some code that throws another exception yet passes the test
}
40
Gishu

L'inspecteur
. dans le test unitaire.


'comment tester mes variables membres sans les rendre publiques ... juste pour les tests unitaires?'

34
Gishu

Configuration excessive - James Carr
Un test qui nécessite une énorme configuration pour même commencer le test. Parfois, plusieurs centaines de lignes de code sont utilisées pour préparer l'environnement à un test, avec plusieurs objets impliqués, ce qui peut rendre difficile de vraiment déterminer ce qui est testé en raison du "bruit" de toute la configuration en cours. (Src: message de James Carr )

34
Gishu

Sonde anale

Un test qui doit utiliser des moyens insensés, illégaux ou autrement malsains pour effectuer sa tâche comme: lire des champs privés en utilisant Java setAccessible (true) ou étendre une classe pour accéder à des champs/méthodes protégés ou avoir à mettre le test dans un certain package pour accéder aux champs/méthodes globaux du package.

Si vous voyez ce modèle, les classes testées utilisent trop de données masquées.

La différence entre cela et l'inspecteur est que la classe sous test essaie de cacher même les choses que vous devez tester. Votre objectif n'est donc pas d'atteindre une couverture de test à 100%, mais de pouvoir tout tester. Pensez à une classe qui n'a que des champs privés, une méthode run() sans arguments et sans getters du tout. Il n'y a aucun moyen de tester cela sans enfreindre les règles.


Commentaire de Michael Borgwardt: Ce n'est pas vraiment un anti-modèle de test, c'est du pragmatisme pour faire face aux déficiences du code testé. Bien sûr, il est préférable de corriger ces lacunes, mais cela peut ne pas être possible dans le cas des bibliothèques tierces.

Aaron Digulla: Je suis en quelque sorte d'accord. Peut-être que cette entrée est vraiment mieux adaptée à un wiki "JUnit HOWTO" et non à un antipattern. Commentaires?

32
Aaron Digulla

Le test sans nom - Nick Pellow

Le test qui est ajouté pour reproduire un bogue spécifique dans le traqueur de bogues et dont l'auteur pense qu'il ne garantit pas son propre nom. Au lieu d'améliorer un test manquant existant, un nouveau test est créé appelé testForBUG123.

Deux ans plus tard, lorsque ce test échoue, vous devrez peut-être d'abord essayer de trouver BUG-123 dans votre outil de suivi des bogues pour comprendre l'intention du test.

26
npellow

Le coup lent

Un test unitaire incroyablement lent. Lorsque les développeurs démarrent, ils ont le temps d'aller aux toilettes, de fumer, ou pire, de lancer le test avant de rentrer chez eux à la fin de la journée. (Src: message de James Carr )

alias les tests qui ne seront pas exécutés aussi souvent qu'ils le devraient

25
Gishu

Le papillon

Vous devez tester quelque chose qui contient des données qui changent tout le temps, comme une structure qui contient la date actuelle, et il n'y a aucun moyen de clouer le résultat à une valeur fixe. La partie laide est que vous ne vous souciez pas du tout de cette valeur. Cela rend simplement votre test plus compliqué sans ajouter de valeur.

La chauve-souris de son aile peut provoquer un ouragan de l'autre côté du monde. - Edward Lorenz, L'effet papillon

20
Aaron Digulla

Le test de scintillement (Source: Romilly Cocking)

Un test qui échoue occasionnellement, pas à des moments précis, et qui est généralement dû aux conditions de course dans le test. Se produit généralement lors du test d'un élément asynchrone, tel que JMS.

Peut-être un super set à l'anti-pattern ' Wait and See ' et ' The Sleeper '.

La construction a échoué, eh bien, exécutez à nouveau la construction. - Développeur anonyme

19
Stuart

Attendez et voyez

Un test qui exécute un code de configuration et doit ensuite "attendre" un certain temps avant de pouvoir "voir" si le code testé fonctionne comme prévu. Un testMethod qui utilise Thread.sleep () ou équivalent est très certainement un test "Wait and See".

En règle générale, vous pouvez voir cela si le test teste du code qui génère un événement externe au système tel qu'un e-mail, une requête http ou écrit un fichier sur le disque.

Un tel test peut également être un Local Hero car il échouera lorsqu'il sera exécuté sur une boîte plus lente ou un serveur CI surchargé.

L'anti-modèle Wait and See ne doit pas être confondu avec The Sleeper .

19
npellow

Appareil partagé de manière inappropriée - Tim Ottinger
Plusieurs cas de test dans le banc d'essai n'utilisent même pas ou n'ont pas besoin de la configuration/démontage. En partie en raison de l'inertie du développeur pour créer un nouveau montage de test ... plus facile d'ajouter simplement un cas de test supplémentaire à la pile

17
Gishu

Le géant

Un test unitaire qui, bien qu'il teste valablement l'objet testé, peut s'étendre sur des milliers de lignes et contenir de nombreux cas de test. Cela peut être un indicateur que le système testé est un God Object (poste de James Carr).

Un signe certain pour celui-ci est un test qui s'étend sur plus de quelques lignes de code. Souvent, le test est si compliqué qu'il commence à contenir des bogues de son propre comportement ou floconneux.

16
Gishu

J'y croirai quand je verrai des GUI clignotantes
Une fixation/obsession malsaine pour tester l'application via son interface graphique "comme un vrai utilisateur"

Tester les règles métier via l'interface graphique est une forme de couplage terrible. Si vous écrivez des milliers de tests via l'interface graphique, puis modifiez votre interface graphique, des milliers de tests sont interrompus.
Plutôt, testez uniquement les éléments de l'interface graphique via l'interface graphique et associez l'interface graphique à un système factice au lieu du système réel, lorsque vous exécutez ces tests. Testez les règles métier via une API qui n'implique pas l'interface graphique. - Bob Martin

"Vous devez comprendre que voir c'est croire, mais aussi savoir que croire c'est voir." - Denis Waitley

15
Gishu

Le dormeur, alias Mont Vésuve - Nick Pellow

Un test qui est destiné à échouer à une heure et une date spécifiques à l'avenir. Cela est souvent dû à une vérification des limites incorrecte lors du test du code qui utilise un objet Date ou Calendrier. Parfois, le test peut échouer s'il est exécuté à une heure très précise de la journée, telle que minuit.

'The Sleeper' ne doit pas être confondu avec l'anti-pattern ' Wait And See '.

Ce code aura été remplacé bien avant l'an 2000 - Beaucoup de développeurs en 1960

14
npellow

L'arbre mort

Un test qui a créé un stub, mais le test n'a pas été réellement écrit.

J'ai vu cela dans notre code de production:

class TD_SomeClass {
  public void testAdd() {
    assertEquals(1+1, 2);
  }
}

Je ne sais même pas quoi en penser.

11
Reverend Gonzo

Le coucou - Frank Carver
Un test unitaire qui se trouve dans un scénario de test avec plusieurs autres, et bénéficie du même processus de configuration (potentiellement long) que les autres tests du scénario de test, mais élimine ensuite tout ou partie des artefacts de la configuration et crée le sien.
Symptôme avancé de: Appareil partagé de manière inappropriée

11
Gishu

a mordu par cela aujourd'hui:

Plancher humide:
Le test crée des données persistantes quelque part, mais le test ne se nettoie pas une fois terminé. Cela entraîne l'échec des tests (le même test ou éventuellement d'autres tests) lors des exécutions de test suivantes .

Dans notre cas, le test a laissé un fichier dans le répertoire "temp", avec les autorisations de l'utilisateur qui a exécuté le test la première fois. Lorsqu'un utilisateur différent a essayé de tester sur la même machine: boom. Dans les commentaires sur le site de James Carr, Joakim Ohlrogge a appelé cela le "Sloppy Worker", et cela faisait partie de l'inspiration pour "Generous Leftovers". J'aime mieux mon nom (moins insultant, plus familier).

11
Zac Thompson

Le test du pôle de quarante pieds

Peur de se rapprocher trop de la classe qu'ils tentent de tester, ces tests agissent à distance, séparés par d'innombrables couches d'abstraction et des milliers de lignes de code de la logique qu'ils vérifient. En tant que tels, ils sont extrêmement fragiles et sensibles à toutes sortes d'effets secondaires qui se produisent lors du voyage épique vers et depuis la classe d'intérêt.

10
bhumphreys

Le test de Turing

Un testcase généré automatiquement par un outil coûteux qui contient de nombreuses assertions glanées dans la classe testée à l'aide d'une analyse de flux de données trop intelligente par moitié. Endort les développeurs dans un faux sentiment de confiance que leur code est bien testé, les déchargeant de la responsabilité de concevoir et de maintenir des tests de haute qualité. Si la machine peut écrire les tests pour vous, pourquoi ne peut-elle pas retirer son doigt et écrire l'application elle-même!

Bonjour stupide. - L'ordinateur le plus intelligent du monde à un nouvel apprenti (d'une vieille bande dessinée d'Amiga).

10
bhumphreys

Le vandalisme environnemental

Un test "unitaire" qui, pour diverses "exigences", commence à se répandre dans son environnement, en utilisant et en définissant des variables/ports d'environnement. L'exécution simultanée de deux de ces tests provoquera des exceptions de "port indisponible", etc.

Ces tests seront intermittents et laisseront les développeurs dire des choses comme "il suffit de le relancer".

Une solution que j'ai vue est de sélectionner au hasard un numéro de port à utiliser. Cela réduit la possibilité d'un conflit, mais ne résout clairement pas le problème. Donc, si vous le pouvez, moquez toujours le code afin qu'il n'alloue pas réellement la ressource non partageable.

10
gcrain

Le Secret Catcher - Frank Carver
Un test qui, à première vue, semble ne faire aucun test, en raison de l'absence d'assertions. Mais "Le diable est dans les détails" .. le test s'appuie vraiment sur une exception à lever et s'attend à ce que le cadre de test capture l'exception et la signale à l'utilisateur comme un échec.

[Test]
public void ShouldNotThrow()
{
   DoSomethingThatShouldNotThrowAnException();
}
10
Gishu

Doppelgänger

Pour tester quelque chose, vous devez copier des parties du code testé dans une nouvelle classe avec le même nom et le même package et vous devez utiliser la magie du chemin de classe ou un chargeur de classe personnalisé pour vous assurer qu'il est visible en premier (afin que votre copie soit choisie vers le haut).

Ce modèle indique une quantité malsaine de dépendances cachées que vous ne pouvez pas contrôler à partir d'un test.

J'ai regardé son visage ... mon visage! C'était comme un miroir mais ça a gelé mon sang.

9
Aaron Digulla

La mère poule - Frank Carver
Une configuration commune qui fait bien plus que les cas de test réels. Par exemple, la création de toutes sortes de structures de données complexes peuplées de valeurs apparemment importantes et uniques lorsque les tests n'affirment que la présence ou l'absence de quelque chose.
Symptôme avancé de: Appareil partagé de manière inappropriée

Je ne sais pas ce que ça fait ... Je l'ajoute quand même, juste au cas où. - Développeur anonyme

7
Gishu

Le test tout

Je ne peux pas croire que cela n'ait pas été mentionné jusqu'à présent, mais les tests ne devraient pas briser le principe de responsabilité unique .

Je l'ai rencontré si souvent, les tests qui enfreignent cette règle sont par définition un cauchemar à maintenir.

7
thegreendroid

Frappeur de ligne

À première vue, les tests couvrent tout et les outils de couverture de code le confirment à 100%, mais en réalité, les tests ne frappent que le code sans aucune analyse de sortie.

code de couverture vs code accessible

6
Ruslan Dzhabbarov

Les jumeaux conjoints

Tests que les gens appellent "Tests unitaires" mais sont vraiment des tests d'intégration car ils ne sont pas isolés des dépendances (configuration de fichiers, bases de données, services, autrement dit les parties non testées dans vos tests que les gens sont devenus paresseux et n'ont pas isolés) et échouent en raison de dépendances qui auraient dû être tronquées ou moquées.

0
PositiveGuy