Convention de dénomination pour les packages de test

11

Nous nommons en fait nos packages de test comme leurs homologues à tester. On se retrouve donc avec cette structure:

src/main/java
    com.hello.world
        helloWorld.java
src/test/java
    com.hello.world
        helloWorldTest.java

J'ai toujours pensé que ce n'était pas assez intelligent car vous ne pouvez pas faire la distinction entre "test" et "to-test" si seulement fourni avec le nom du package. D'un autre côté, je n'ai pas vraiment trouvé de cas où cela soit important. Est-ce une bonne pratique d'avoir les mêmes conventions de dénomination pour les deux packages (pour les cas de test et les classes source)? Sinon, quelle serait une meilleure approche?

OddDev
la source
1
Je ne sais pas si c'est une bonne pratique, mais c'est une pratique populaire. L'autre option (pour mettre "Test" dans le nom du package, les noms de méthode, etc.) sent un peu trop la "dénomination de Schtroumpf". Comme vous le dites, il est difficile de penser à un cas où le fait de ne pas pouvoir faire la "distinction" entre "tester" et "tester" s'il était uniquement fourni avec le nom du package "serait un problème.
David Arno
@DavidArno Merci pour votre contribution :) Comment éviter alors le smurf-naming? Je veux dire que nous finirions avec com.hello.world.test.helloWorld.java, n'est-ce pas?
OddDev
Le problème du "schtroumpf" est plus important lorsque vous avez une méthode XXXTest()en com.hello.world.test.helloWorldTest.java. L'avis général serait de ne faire apparaître "Test" qu'une seule fois dans le chemin, donc (a) utilisez test dans le nom du package (et nommez le fichier de test de la même manière que le fichier sous test) ou (b) définissez le nom du package comme même et ajoutez "test" au nom de fichier / classe.
David Arno
@DavidArno Ah, merci pour la clarification! J'ai mal fait votre premier commentaire. Je l'ai maintenant.
OddDev
Eh bien, je dirais que, si ce n'était pas clair, je me suis trompé mon premier commentaire :)
David Arno

Réponses:

11

C'est une bonne convention.

Parfois, vous voulez également écrire des tests unitaires pour les classes et méthodes privées des packages. Vous ne pourrez pas les appeler à partir d'une classe de test unitaire placée dans un autre package.

Il ne devrait pas y avoir de confusion quant au fait d'avoir des classes de tests unitaires dans le même espace de noms car elles ne devraient pas se trouver dans le chemin de classe lors de la compilation ou de l'exécution du code de production.

Voici un exemple d'un petit module avec une interface publique, une classe d'usine publique et deux classes d'implémentation de paquet privé:

src/main/java:
    com.hello.transmogrifier
        public interface Transmogrifier
        public class TransmogrifierFactory
        class MapTransmogrifier implements Transmogrifier
        class ListTransmogrifier implements Transmogrifier

scr/test/java:
    com.hello.transmogrifier
        public class TransmogrifierFactoryTest
        public class MapTransmogrifierTest
        public class ListTransmogrifierTest

Masquer les implémentations de l'interface Transmogrifier pourrait être un choix de conception valide. C'est peut-être la responsabilité de la classe d'usine de choisir la mise en œuvre.

Étant donné que les implémentations sont privées du package, vous devez placer les classes de test unitaire dans le même package si vous souhaitez les tester directement. Si vous avez vos classes de tests unitaires dans un autre package, vous n'avez accès directement à l'interface publique et à la classe d'usine qu'à partir de vos tests.

VIENS DE
la source
1
Msgstr "Habituellement, vous voulez également écrire des tests unitaires pour les classes et les méthodes de paquet privé". Non! C'est vraiment une mauvaise pratique. Les types privés de package sont des détails d'implémentation et ne doivent jamais être testés directement. Testez uniquement les API publiques.
David Arno
1
@DavidArno Je ne suis pas d'accord. Cependant, j'ai remplacé le mot «habituellement» par le mot «parfois» pour éviter cette discussion particulière.
VENIR DU
1
Vous n'êtes peut-être pas d'accord avec tout ce que vous voulez, mais tester le fonctionnement interne d'un morceau de code conduit à la fois à un couplage étroit entre ces fonctionnements internes et les tests et à des tests fragiles qui se cassent facilement lors d'une refactorisation même simple. C'est une très mauvaise pratique.
David Arno
Si je veux m'assurer que toutes mes implémentations Transmogrifier fonctionnent, peu importe ce que fait l'usine, alors je vais écrire des tests unitaires qui testent chaque implémentation. Notez que les implémentations ont une API publique partagée même si les classes sont privées au package. Ces tests ne devraient pas s'arrêter à moins que je ne modifie l'API publique. En fait, j'écrirais probablement un test générique pour un transmogrificateur, puis je l'exécuterais pour chaque implémentation. Bien qu'il soit possible d'obtenir chaque implémentation en utilisant l'usine, il est préférable de ne pas avoir cette dépendance lors du test des transmogrifiants.
VENIR DU
Puis , un jour, vous regardez MapTransmogrifieret ListTransmogrifieret décider qu'ils pourraient être transformés en une seule classe, de sorte que vous créez ListMapTransmogrifier, modifiez l'usine à l' utiliser et de supprimer les deux classes. Le code ne compile plus, vous devez donc modifier chaque test dans les deux MapTransmogrifierTestet ListTransmogrifierTestle faire compiler. Un test échoue. Était-ce dû à la modification des tests ou à la création ListMapTransmogrifier? Sort le débogueur pour le découvrir ... alternativement lorsque les tests utilisent l'usine, vous faites ce refactor et tout compile toujours ...
David Arno