J'écris des tests unitaires JUnit pour mes classes.
Est-il préférable d'avoir une classe distincte pour chaque méthode, ou d'avoir une seule classe de test pour chaque classe réelle?
L'organisation de vos tests n'a pas d'importance par rapport à l'importance de les avoir.
La chose la plus importante pour une bonne suite de tests est qu'elle couvre toutes les fonctionnalités; ce qui garantit que chaque fois qu'un défaut de régression est introduit, vous le remarquerez immédiatement. Que ce soit pour écrire un test pour chaque méthode, un test pour chaque combinaison de valeurs d'entrée d'une méthode, ou même un test pour chaque chemin de code possible dans cette méthode est moins important. Qu'il s'agisse d'organiser ces tests en quelques ou plusieurs classes de tests est encore moins important: une suite de tests doit toujours réussir pleinement, donc peu importe qu'elle échoue à l'un des trois ou deux des dix-sept tests - les deux sont faux et doivent être fixé.
Bien sûr, le code de test est également du code, il doit donc suivre les meilleures pratiques normales pour être maintenable, modulaire, etc. Mais cela doit être décidé par la qualité de la suite de tests elle-même, et non par la relation entre les classes de test et les classes qu'ils testent. Les deux politiques que vous mentionnez peuvent vous aider à vous rappeler où trouver des choses si vous les suivez de manière cohérente, mais pour cela, la cohérence est plus importante que le choix de la politique.
Pour votre question spécifique, la convention JUnit, est d'avoir une correspondance 1: 1 entre vos classes d'application (Foo1.Java
, Foo2.Java
) et les classes de test JUnit (Foo1Test.Java
, Foo2Test.Java
).
Cela dit, je suis entièrement d'accord avec la mise en évidence par Kilian de l'importance de l'esprit/des objectifs des tests unitaires sur tous les schémas organisationnels qui pourraient être utilisés. Choisissez des conventions et respectez-les la plupart du temps, tout en autorisant prudemment des exceptions à vos conventions, lorsqu'elles sont justifiées.
Est-il préférable d'avoir une classe distincte pour chaque méthode, ou d'avoir une seule classe de test pour chaque classe réelle?
Si vous avez besoin d'écrire des classes de test distinctes pour les méthodes d'une classe, alors vous avez une mauvaise conception. Les méthodes doivent être petites, faciles à lire, faciles à tester et faciles à modifier. Les tests pourraient être un peu plus longs que le code d'origine en raison de la constitution des données de test, des moqueries, etc., mais ne devraient pas être beaucoup plus longs. S'ils le sont, votre classe testée est trop complexe et fait à coup sûr plus d'une chose (principe de responsabilité unique): Travaillez sur votre design.
Je pense que "une classe de test par méthode" et "une classe de test par classe" sont généralement trop extrêmes.
En général, vous voulez avoir une vérification par méthode de test/test unitaire. Par exemple, il peut s'agir de plusieurs assertions pour vérifier qu'un list.isEmpty = true
et list.Length = 0
, donc une méthode de test/test unitaire par comportement.
Cela permet de trouver facilement un nom de méthode de test qui décrit le comportement. Vous souhaitez regrouper les méthodes de test dans une classe de test, donc lorsque vous lisez le test classname.test method
, Ca a du sens. Habituellement, ceux-ci ont un code de configuration partagé qui est ensuite facile à mettre dans la configuration/le montage de test. Selon la classe testée, il peut s'agir d'une classe de test pour la classe entière et également d'une classe de test pour une méthode. Mais généralement, ce sera quelque part entre les deux.
Comme avec le code normal, vous voulez que les tests soient aussi lisibles que possible. Ce qui m'aide, c'est de suivre le style BDD donner-quand-alors ou organiser-agir-affirmer pour organiser le code de test. Une classe de test pourrait avoir cela, c'est la configuration. Ensuite, chaque méthode de test de cette classe utilise cette donnée (ou une partie de celle-ci) et en a une quand et une alors.
Considérez également les tests unitaires comme une documentation sur la façon d'utiliser les fonctionnalités de la classe testée. Avec de bons tests unitaires, vous pouvez lire les tests pour savoir comment utiliser les fonctionnalités de la classe que vous souhaitez utiliser, et quels seront les effets exactement.
Lorsque quelque chose se casse et qu'un test unitaire échoue, vous voulez qu'il soit aussi facile que possible de comprendre ce qui s'est cassé, une assertion par test aide beaucoup ici. Lorsqu'il y a plusieurs assertions dans un test, seul le premier échoue, puis la méthode se termine, vous ne savez donc pas si l'autre comportement testé dans les tests suivants est également rompu jusqu'à ce que vous corrigiez ce qui a fait échouer la première assertion. Avec une seule assertion, toutes vos autres méthodes de test sont toujours exécutées et il est beaucoup plus rapide de comprendre la profondeur de l'échec.
Bien sûr, je suis d'accord avec Kilian Foth: en pratique, vous pouvez avoir la chance de faire quelques tests unitaires pour le code sur lequel vous travaillez. Et tout petit test localisé vaut mieux que pas de test du tout, ou seuls les gros tests d'intégration qui s'exécutent sur le serveur de build prennent beaucoup de temps et ne sont généralement pas très localisés (ils ne vous disent pas rapidement où est l'erreur - vous je vais devoir y travailler un peu).
Je pense qu'il est juste que chaque classe ait sa classe de test. L'idée est de centraliser tous les tests unitaires liés à la classe cible dans une seule classe de test. Ensuite, par exemple, MyClass.Java
aura sa classe de test appelée MyClassTest.Java
.
Il est également recommandé de demander à vos collègues s'il existe des documents sur la façon de tester dans votre entreprise ou sur la façon dont ils suivent. Si vous suivez leurs directives, cela rend vos tests plus lisibles pour les autres.