Les tests unitaires ne devraient-ils couvrir que les logiciels «fonctionnels»

9

Nous utilisons StructureMap dans un nouveau projet de développement logiciel. L'un des membres de l'équipe a mis en œuvre un test unitaire qui teste essentiellement la configuration du conteneur StructureMap . Il le fait en procédant comme suit;

  • Compte le nombre d'instances d'assemblys configurés pour les classes dans notre espace de noms d'application.
  • Définit les instances attendues au niveau de la classe
  • Affirme que les instances attendues correspondent au nombre total d'instances trouvées.
  • Affirme que les instances attendues correspondent à celles définies dans le test

Un exemple de ceci est;

var repositories = container.GetAllInstances<IEnvironmentRepository>();
Assert.AreEqual(1, repositories .Count());
foundInstances = foundInstances + repositories .Count();

Nous avons également des «tests unitaires» pour la classe suivante;

public MyClass(IEnvironmentRepository environmentRepository)
        {

        }

Dans ces tests, nous nous moquons de IEnvironmentRepository, donc nous ne l'injecterions pas du conteneur comme cela se produirait dans le système actif.

Un collègue a ignoré le test unitaire dans la configuration structuremap avec un commentaire du type "Le test unitaire teste uniquement sa propre configuration". C'était évidemment le but du test et à mon avis c'est parfaitement valable. J'ai demandé au gars qui a ignoré le test de supprimer la configuration de structuremap IEnvironmentRepository(avec le test toujours ignoré) et d'exécuter la suite de tests unitaires complète, ils ont tous réussi. Nous avons ensuite exécuté l'application et elle est tombée car la configuration du conteneur n'était plus valide. À mon avis, cela prouvait la valeur du test, mon collègue n'était toujours pas d'accord. Il a simplement déclaré que nous ne devrions pas tester la configuration, mais je considère que cela relève bien du mandat d'un test unitaire.

Donc, un certain nombre de questions;

  • Est-ce un test unitaire valide - Nous testons la configuration de notre conteneur, pas que la structure de carte fonctionne (mais je peux voir le chevauchement)
  • Sinon, comment pouvez-vous valider la configuration sans la tester. Comment pouvez-vous empêcher quelqu'un de supprimer accidentellement une ligne de code requise et de l'archiver?
  • Le MyClasstest unitaire doit-il résoudre l'instance de IEnvironmentRepositorydu conteneur et le transmettre?
ChrisBint
la source
10
9 désaccords sur 10 sur les tests proviennent du fait que les frameworks prennent en charge les tests automatisés sous toutes leurs formes, et les gens veulent entrer dans la sémantique pour savoir si un test automatisé particulier est un bon test unitaire approprié ou non. Le test que vous décrivez ressemble au genre de test de test pas tout à fait unitaire qui peut très bien être utile d'avoir et d'automatiser (et de s'exécuter lors de l'archivage) - ne l'appelez tout simplement pas un test unitaire. Demandez si votre collègue dormirait mieux la nuit si le test vivait dans sa propre fonction / dossier qui était clairement séparé.
Jeroen Mostert
2
C'est aussi mon avis, probablement utile, et bien qu'il ne s'agisse pas strictement d'un test unitaire, il ajoute de la valeur et cela a été prouvé. Sa réponse a été que les autres tests unitaires auraient repris cela, mais à mon avis, s'ils étaient écrits comme des tests unitaires stricts, vous seriez moqués des dépendances et ne sauriez donc jamais si la configuration était valide jusqu'à ce que vous l'utilisiez.
ChrisBint
4
Votre collègue a raison quand il dit de ne pas tester la configuration, dans la mesure où une configuration authentique qui peut réellement varier selon le déploiement ne peut / ne doit pas être testée - qui dit "rouge" est faux et "bleu" ne l'est pas? Le test serait étroitement couplé à une configuration. Mais la configuration qui est liée aux artefacts de code est un peu une exception, car elle ne varie pas et il existe clairement des moyens de se tromper. Idéalement, une telle configuration devrait être générée au moment de la construction à partir des métadonnées DRY, mais lorsque cela n'est pas possible, un test comme celui-ci ajoute de la valeur. Mieux qu'une erreur de déploiement évitable.
Jeroen Mostert
2
Ce que vous décrivez ne teste pas une unité, il teste la configuration d'un logiciel tiers. Il est extrêmement utile d'avoir des tests qui testent ces choses, mais ce sont des tests d'intégration, pas des tests unitaires, et la déconnexion peut être à l'origine du désaccord.
Phoshi
3
@ChrisBint Dieu merci, j'ai écrit moi-même un tas de tests de conteneurs. Ils ont beaucoup de valeur, ce ne sont tout simplement pas des tests unitaires. C'est bien, les tests d'intégration sont extrêmement précieux pour détecter les choses que les tests unitaires ne peuvent pas .
Phoshi

Réponses:

13

Il s'agit d'un test automatisé parfaitement valide. Je les appelle des "tests d'architecture" car ils vérifient la solidité des composants squelettiques de votre base de code.

Le conteneur IoC est-il capable de résoudre et de composer toutes les arborescences d'objets dans l'application? Le mappeur automatique peut-il mapper entre tous ses objets enregistrés sans échec? La couche centrale d'une architecture Oignon ne fait-elle référence à rien d'extérieur?

Ces tests peuvent vous faire gagner beaucoup de temps lorsqu'un bogue de configuration se glisse, en pointant le coupable exact. De bons cadres vous donneront des messages d'erreur très précis sur ce qui ne va pas et vous les obtiendrez dès que vous exécuterez les tests (idéalement, en continu) au lieu d'être enfouis au fond d'une trace de pile d'exécution si vous êtes chanceux.

Qu'il s'agisse de tests unitaires ... probablement pas, mais ils fonctionnent toujours en mémoire pour la plupart et fonctionnent assez rapidement. Là encore, je ne sais pas, ce n'est pas comme s'il y avait une définition universellement acceptée du test unitaire.

guillaume31
la source
Ironiquement, c'est à peu près comment je l'ai expliqué à mon collègue et même avec la validation (supprimer l'une des instances de conteneur et exécuter l'application), il ne voyait toujours aucune valeur. Je comprends que chacun a sa propre opinion, et j'ai exprimé la mienne;) J'adore le terme "test d'architecture", je vais voler ça!
ChrisBint
6

Le problème avec un test comme celui-ci qui teste les internes du programme, plutôt qu'une exigence de celui-ci. Est-ce que le test peut échouer même si le programme fonctionne comme requis.

Dans votre cas, chaque fois que vous modifiez la configuration du conteneur, vous avez peut-être une nouvelle dépendance à injecter, vous cassez votre test.

En outre, si vous ajoutez l'exigence de dépendance supplémentaire, mais oubliez de l'ajouter au conteneur et modifiez le test du conteneur. tout passera, mais votre programme plantera.

Un meilleur test automatisé serait de démarrer le programme et de voir s'il se bloque.

Vous devez détecter ces types d'erreur lors des tests d'intégration ou d'interface utilisateur, même s'ils tombent dans les tests unitaires.

Cela dit, la complexité croissante de la configuration des conteneurs est pénible. Peut-être que certains «mauvais» tests en valent la peine.

Ewan
la source
1

Test unitaire du code de test. Tout ce qui est en dehors de cela est un "autre" test automatisé - appelez-le comme vous voulez. Vous semblez tester la configuration ici. Si la configuration peut changer en fonction de l'environnement, elle n'appartient pas à un test unitaire. Pensez à ajouter un attribut de test pour indiquer que le test est d'un type différent des autres tests.

Robbie Dee
la source
La configuration est statique, elle n'est pas pilotée par l'environnement, toutes les classes qui existent dans la configuration seront utilisées sur tous les environnements de la même manière. Oui, le nombre d'instances qui pourraient être dans la configuration doit correspondre au nombre d'instances dans la configuration, qui fait partie du test. Comme mon exemple l'a montré, la suppression de IEnvironmentRepository a permis aux autres tests unitaires de passer. Le test de conteneur spécifique aurait échoué sur 2 assertions; 1 - Le nombre total de déclarations d'instance possibles ne correspond pas, et 2 - le nombre spécifique d'instannces de IEnvironmentRepository ne correspond pas.
ChrisBint
1
La justesse du conteneur est définie par le codeur. Le fait que le code sous test et le test lui-même doivent changer pour chaque modification déclenche immédiatement la sonnerie d'alarme. DI est un moyen pour une fin et non la fin en soi. Il est parfaitement possible d'écrire du code dans un style DI sans structuremap ergo ce n'est pas un test unitaire de bonne foi à mon avis. Le conteneur doit bien sûr être prouvé, mais l'efficacité de le faire avec des tests automatisés semble être quelque peu théorique avec les informations limitées fournies ici.
Robbie Dee
2
Les tests unitaires ont mis 10 minutes à se faire. Le déploiement pourrait prendre plus d'une heure.
ChrisBint
1
Étant donné qu'une partie du test unitaire valide spécifiquement l'existence d'une seule ligne dans la configuration, je ne sais pas comment cela n'aurait pas pu être plus isolé. Le compte général avec lequel je suis d'accord.
ChrisBint
1
Il pourrait y avoir un certain kilométrage en eux alors - un jugement s'impose vraiment pour vous. Mais ils doivent être séparés physiquement ou via un attribut.
Robbie Dee
0

La responsabilité du conteneur d'injection de dépendance est de coller différents modules dans une application de travail .

Si vous écrivez des tests automatisés pour votre application - vous devriez avoir quelques "tests d'intégration (ou d'acceptation) qui exécutent des tests" de bout en bout ", qui testeront l'ensemble du pipeline de votre application, que tous les modules impliqués dans un cas de test particulier sont collés ensemble correctement .

Ces tests d'intégration échoueront donc si le conteneur d'injection de dépendance n'a pas été configuré correctement. Ce qui rend les tests unitaires pour le conteneur lui-même inutiles, car le test d'intégration devrait montrer d'éventuelles erreurs dans la configuration du conteneur.

Vous n'avez pas besoin de couvrir tous les cas de test possibles dans les tests d'intégration, juste un cas de test par fonctionnalité qui couvre le chemin complet de l'interface utilisateur à la base de données.

Si les cas de test d'intégration ne couvrent pas l'instanciation d'une dépendance particulière - vous ajoutez simplement celle-ci.

Avec les tests d'intégration, vous pouvez modifier librement les conteneurs sans réécrire les tests unitaires pour leur configuration.

Fabio
la source
0

OMI, les réponses sont:

  1. Est-ce un test unitaire valide - Nous testons la configuration de notre conteneur, pas que la structure de carte fonctionne (mais je peux voir le chevauchement)

    • C'est un test unitaire valide pour structuremap , pas pour votre projet, car un test unitaire teste du code spécifique, se moquant de toutes les dépendances si nécessaire afin de tester la logique implémentée. La logique de configuration est implémentée à l'intérieur de structuremap, donc cette bibliothèque doit être bien testée et doit contenir des tests unitaires comme celui que vous avez mentionné, et plus encore: elle devrait contenir des centaines de tests comme celui-ci, se moquant dynamiquement de plusieurs configurations à l'exécution et testant pour voir si le le récipient se comporte comme il se doit.
  2. Sinon, comment pouvez-vous valider la configuration sans la tester. Comment pouvez-vous empêcher quelqu'un de supprimer accidentellement une ligne de code requise et de l'archiver?

    • Vous pouvez tester la configuration manuellement dans l'environnement requis, et vous pouvez également créer une automatisation pour cela (test automatisé), qui teste la configuration spécifique dont vous avez besoin (pas besoin de se moquer des choses à l'exécution).
  3. Le test unitaire MyClass doit-il résoudre l'instance de IEnvironmentRepository à partir du conteneur et le transmettre?

    • Non, c'est un test unitaire parfait, car vous vous moquez de la dépendance et testez la logique MyClass de manière isolée.
Emerson Cardoso
la source
-1

UnitTest vérifie le comportement souhaité d'une unité en séparation .

Cela signifie que tout type de configuration ne fait pas partie des tests unitaires .

Néanmoins, vous devriez avoir des tests automatisés pour vos configurations, mais ce ne sont pas des UnitTests ...

Timothy Truckle
la source
Où obtenez-vous la définition des unités?
ChrisBint
J'aime celui de Roy Osherove dans The Art Of Unittesting : A Unit est un morceau de code (de production) qui a la même raison de changer. Dans mon monde, cela va généralement d'une seule classe à trois ou cinq ...
Timothy Truckle
C'est le code de production qui est testé.
ChrisBint
Je voulais juste distraire les nitpickers , ne m'attendant pas à ce que cela fonctionne aussi dans l'autre sens ...; o)
Timothy Truckle