Si vous avez une énumération avec des valeurs uniquement (aucune méthode comme on pourrait le faire en Java), et cette énumération fait partie de la définition métier du système, doit-on écrire des tests unitaires pour cela?
Je pensais qu'ils devraient être écrits, même s'ils pouvaient sembler simples et redondants. Je considère que ce qui concerne la spécification métier devrait être explicitement écrit dans un test, que ce soit avec unit / integration / ui / etc. tests ou en utilisant le système de type de la langue comme méthode de test. Étant donné que les valeurs qu'une énumération (par exemple en Java) doit avoir, du point de vue de l'entreprise, ne peuvent pas être testées en utilisant le système de type, je pense qu'il devrait y avoir un test unitaire pour cela.
Cette question n'est pas similaire à celle-ci car elle ne règle pas le même problème que le mien. Dans cette question, il y a une fonction métier (savePeople) et la personne se renseigne sur l'implémentation interne (forEach). Là-bas, il y a une couche métier intermédiaire (la fonction sauver les gens) encapsulant la construction du langage (forEach). Ici, la construction du langage (enum) est celle utilisée pour spécifier le comportement d'un point de vue commercial.
Dans ce cas, le détail d'implémentation coïncide avec la "vraie nature" des données, c'est-à-dire un ensemble (au sens mathématique) de valeurs. On pourrait sans doute utiliser un ensemble immuable, mais les mêmes valeurs devraient toujours y être présentes. Si vous utilisez un tableau, la même chose doit être effectuée pour tester la logique métier. Je pense que l'énigme ici est le fait que la construction du langage coïncide très bien avec la nature des données. Je ne sais pas si je me suis bien expliqué
la source
Réponses:
Non, ce sont juste des états.
Fondamentalement, le fait que vous utilisiez une énumération est un détail d'implémentation ; c'est le genre de chose que vous voudrez peut-être réorganiser dans un design différent.
Tester l'énumération de l'exhaustivité est analogue à tester que tous les entiers représentables sont présents.
Cependant, tester les comportements pris en charge par les énumérations est une bonne idée. En d'autres termes, si vous partez d'une suite de tests réussie et commentez une valeur d'énumération unique, alors au moins un test doit échouer (les erreurs de compilation étant considérées comme des échecs).
la source
Hearts
,Spades
,Diamonds
,Clubs
] si vous n'avez jamais de carte que si une carte est rouge / noire?null_ptr
erreur. Maintenant qui a un code d'erreur via l'énumération. Le code recherchant unenull_ptr
erreur recherche également le code via l'énumération. Il peut donc avoir une valeur5
(par exemple). Vous devez maintenant ajouter un autre code d'erreur. L'énumération est modifiée (disons que nous en ajoutons une nouvelle en haut de l'énumération) La valeur denull_ptr
est maintenant6
. Est-ce un problème? vous retournez maintenant un code d'erreur de6
et testez pour6
. Tant que tout est logiquement cohérent, tout va bien, malgré ce changement qui brise votre test théorique.Vous ne testez pas une déclaration d' énumération . Vous pouvez tester si l'entrée / sortie de fonction a les valeurs d'énumération attendues. Exemple:
Vous n'écrivez pas de tests vérifiant puis enum
Parity
définit les nomsEven
etOdd
. Un tel test serait inutile car vous répéteriez simplement ce qui est déjà indiqué par le code. Dire deux fois la même chose ne le rend pas plus correct.Vous faites des tests d'écriture vérification par
GetParity
exemple renverrontEven
0,Odd
pour 1 et ainsi de suite. Ceci est précieux car vous ne répétez pas le code, vous vérifiez le comportement du code, indépendamment de l'implémentation. Si le code à l'intérieurGetParity
était complètement réécrit, les tests seraient toujours valides. En effet, les principaux avantages des tests unitaires sont qu'ils vous donnent la liberté de réécrire et de refactoriser le code en toute sécurité, en garantissant que le code fonctionne toujours comme prévu.Mais si vous disposez d'un test qui garantit qu'une déclaration d' énumération définit les noms attendus, toute modification que vous apporterez à l'énumération à l'avenir vous obligera à modifier également le test. Cela signifie que ce n'est pas seulement deux fois plus de travail, cela signifie également que tout avantage du test unitaire est perdu. Si vous devez changer de code et tester en même temps , il n'y a aucune garantie contre l'introduction de bogues.
la source
S'il y a un risque que la modification de l'énumération casse votre code, alors bien sûr, tout ce qui a l'attribut [Flags] en C # serait un bon cas car l'ajout d'une valeur entre 2 et 4 (3) serait un 1 et 2 au niveau du bit plutôt qu'un article discret.
C'est une couche de protection.
Vous devriez envisager d'avoir un code de pratique enum que tous les développeurs connaissent. Ne vous fiez pas aux représentations textuelles de l'énumération qui est courante, mais cela pourrait entrer en conflit avec vos directives de sérialisation.
J'ai vu des gens "corriger" la mise en majuscule des entrées d'énumération, les trier par ordre alphabétique ou par un autre regroupement logique qui ont tous cassé d'autres morceaux de mauvais code.
la source
Non, un test vérifiant qu'une énumération contient toutes les valeurs valides et rien de plus répète essentiellement la déclaration de l'énumération. Vous ne feriez que tester que le langage implémente correctement la construction enum qui est un test insensé.
Cela étant dit, vous devez tester le comportement qui dépend des valeurs d'énumération. Par exemple, si vous utilisez les valeurs d'énumération pour sérialiser des entités en json ou autre, ou si vous stockez les valeurs dans une base de données, vous devez tester le comportement de toutes les valeurs de l'énumération. De cette façon, si l'énumération est modifiée, au moins l'un des tests devrait échouer. Dans tous les cas, ce que vous testeriez, c'est le comportement autour de votre énumération, pas la déclaration d'énumération elle-même.
la source
Votre code devrait fonctionner correctement indépendamment des valeurs réelles d'une énumération. Si tel est le cas, aucun test unitaire n'est nécessaire.
Mais vous pouvez avoir du code où la modification d'une valeur d'énumération va casser les choses. Par exemple, si une valeur d'énumération est stockée dans un fichier externe, et après avoir changé la valeur d'énumération, la lecture du fichier externe donnera le mauvais résultat. Dans ce cas, vous aurez un GRAND commentaire près de l'énumération avertissant quiconque de ne modifier aucune valeur, et vous pouvez très bien écrire un test unitaire qui vérifie les valeurs numériques.
la source
En général, le simple fait de vérifier qu'une énumération possède une liste de valeurs codées en dur n'est pas très utile, comme l'ont dit d'autres réponses, car il suffit alors de mettre à jour test et énumération ensemble.
J'ai eu une fois un cas où un module utilisait des types d'énumération de deux autres modules et mappés entre eux. (L'une des énumérations avait une logique supplémentaire avec elle, l'autre était pour l'accès DB, les deux avaient des dépendances qui devraient être isolées les unes des autres.)
Dans ce cas, j'ai ajouté un test (dans le module de mappage) qui a vérifié que toutes les entrées d'énumération dans l'énumération source existent également dans l'énumération cible (et donc que le mappage fonctionnerait toujours). (Dans certains cas, j'ai également vérifié l'inverse.)
De cette façon, lorsque quelqu'un a ajouté une entrée d'énumération à l'une des énumérations et a oublié d'ajouter l'entrée correspondante à l'autre, un test a commencé à échouer.
la source
Les énumérations sont simplement des types finis, avec des noms personnalisés (espérons-le significatifs). Une énumération peut n'avoir qu'une seule valeur, comme celle
void
qui ne contient quenull
(certaines langues appellent celaunit
, et utilisent le nomvoid
d'une énumération sans éléments!). Il peut avoir deux valeurs, comme cellebool
qui afalse
ettrue
. Il peut avoir trois, commecolourChannel
avecred
,green
etblue
. Etc.Si deux énumérations ont le même nombre de valeurs, elles sont alors "isomorphes"; c'est-à-dire que si nous supprimons systématiquement tous les noms, nous pouvons en utiliser un à la place d'un autre et notre programme ne se comportera pas différemment. En particulier, nos tests ne se comporteront pas différemment!
Par exemple,
result
contenirwin
/lose
/draw
est isomorphe à ce qui précèdecolourChannel
, car nous pouvons remplacer par exemplecolourChannel
parresult
,red
avecwin
,green
aveclose
etblue
avecdraw
, et tant que nous le faisons partout (producteurs et consommateurs, analyseurs et sérialiseurs, entrées de base de données, fichiers journaux, etc. ), il n'y aura alors aucun changement dans notre programme. Tous les "colourChannel
tests" que nous avons écrits passeront toujours, même s'il n'y en acolourChannel
plus!De plus, si une énumération contient plusieurs valeurs, nous pouvons toujours réorganiser ces valeurs pour obtenir une nouvelle énumération avec le même nombre de valeurs. Étant donné que le nombre de valeurs n'a pas changé, le nouvel arrangement est isomorphe à l'ancien, et donc nous pourrions changer tous les noms et nos tests passeraient toujours (notez que nous ne pouvons pas simplement changer la définition; nous devons désactiver également tous les sites d'utilisation).
Cela signifie que, en ce qui concerne la machine, les énumérations sont des "noms distinctifs" et rien d'autre . La seule chose que nous pouvons faire avec une énumération est de déterminer si deux valeurs sont identiques (par exemple
red
/red
) ou différentes (par exemplered
/blue
). Voilà donc la seule chose qu'un «test unitaire» peut faire, par exempleComme le dit @ jesm00, un tel test vérifie l' implémentation du langage plutôt que votre programme. Ces tests ne sont jamais une bonne idée: même si vous ne faites pas confiance à l'implémentation du langage, vous devez le tester de l'extérieur , car il ne peut pas faire confiance pour exécuter les tests correctement!
Voilà donc la théorie; qu'en est-il de la pratique? Le principal problème avec cette caractérisation des énumérations est que les programmes du `` monde réel '' sont rarement autonomes: nous avons des versions héritées, des déploiements à distance / intégrés, des données historiques, des sauvegardes, des bases de données en direct, etc. donc nous ne pouvons jamais vraiment `` basculer '' toutes les occurrences d'un nom sans manquer certaines utilisations.
Pourtant, de telles choses ne relèvent pas de la «responsabilité» de l'énumération elle-même: la modification d'une énumération peut interrompre la communication avec un système distant, mais inversement, nous pouvons résoudre un tel problème en modifiant une énumération!
Dans de tels scénarios, l'ENUM est un hareng saur: si un système dont il a besoin d'être cette façon, et un autre , il doit être que ça? Ça ne peut pas être les deux, peu importe le nombre de tests que nous écrivons! Le vrai coupable ici est l'interface d'entrée / sortie, qui devrait produire / consommer des formats bien définis plutôt que "quel que soit l'entier choisi par l'interprète". La vraie solution est donc de tester les interfaces d'E / S : avec des tests unitaires pour vérifier qu'il analyse / imprime le format attendu, et avec des tests d'intégration pour vérifier que le format est bien accepté par l'autre côté.
Nous pouvons encore nous demander si l'énumération est «suffisamment exercée», mais dans ce cas, l'énumération est à nouveau un hareng rouge. Ce qui nous préoccupe réellement, c'est la suite de tests elle-même . Nous pouvons gagner en confiance ici de deux manières:
red
, et que nous testons uniquement avecred
, alors nous avons une couverture à 100%. Un vérificateur de propriétés va (essayer de) générer des contre-exemples à nos assertions, comme générer les valeursgreen
et queblue
nous avons oublié de tester.la source
Les tests unitaires concernent les unités de test.
https://en.wikipedia.org/wiki/Unit_testing
Un test automatisé pour une énumération déclarée consisterait à tester l'intégrité du langage et de la plate-forme sur laquelle il s'exécute plutôt que la logique dans du code créé par le développeur. Cela ne servirait à rien - documentation incluse puisque le code déclarant l'énumération sert de documentation aussi bien que de code qui le testerait.
la source
Vous devez tester le comportement observable de votre code, les effets des appels de méthode / fonction sur l'état observable. Tant que le code fait la bonne chose, tout va bien, vous n'avez pas besoin de tester autre chose.
Vous n'avez pas besoin d'affirmer explicitement qu'un type d'énumération a les entrées que vous attendez, tout comme vous n'affirmez pas explicitement qu'une classe existe réellement ou qu'elle a les méthodes et les attributs que vous attendez.
En fait, en testant le comportement, vous affirmez implicitement que les classes, méthodes et valeurs impliquées dans le test existent, vous n'avez donc pas besoin de l'affirmer explicitement.
Notez que vous n'avez pas besoin de noms significatifs pour que votre code fasse la bonne chose, c'est juste une commodité pour les personnes qui lisent votre code. Vous pouvez faire fonctionner votre code avec des valeurs enum comme
foo
,bar
... et des méthodes commefrobnicate()
.la source