Bonne pratique de développement JUnit
Résolu
Jithel
Messages postés
843
Date d'inscription
Statut
Membre
Dernière intervention
-
Jithel Messages postés 843 Date d'inscription Statut Membre Dernière intervention -
Jithel Messages postés 843 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
J'aurais une question vis-à-vis des bonnes pratiques de développement pour les tests unitaires avec JUnit. Bien que je n'ai trouvé aucun article à ce sujet (il existe sans doute des livres), je suis face à un problème :
Il est souvent nécessaire d'écrire plusieurs tests pour un même bloc unitaire (que l'on appellera ici fonction). Plutôt que de tout mettre dans une fonction de test, il est judicieux d'en écrire plusieurs pour avoir une meilleure séparation des tests et un meilleur suivi en cas d'échec de l'un d'eux.
Exemple :
Maintenant, considérons que je développe 5 tests unitaires par fonction pour une classe qui contient une dizaine de fonction. Cela fait une cinquantaine de tests unitaires dans la même classe. Ne serait-il pas plus judicieux de créer une classe par test de fonction ? Plutôt que d'avoir une classe avec 50 tests unitaires, ne serait-il pas mieux d'avoir 10 classes avec 5 tests unitaires ? Par "mieux", j'entend la maintenance et l'évolutivité du code.
Exemple :
Il y a des inconvénients à faire ça : nom de classe trop long pour les décrire précisément, peut-être problème de performance (car 10 instances de classe plutôt qu'une), des classes parfois trop courtes (si j'écris un test unitaire pour une fonction).
J'aurais une question vis-à-vis des bonnes pratiques de développement pour les tests unitaires avec JUnit. Bien que je n'ai trouvé aucun article à ce sujet (il existe sans doute des livres), je suis face à un problème :
Il est souvent nécessaire d'écrire plusieurs tests pour un même bloc unitaire (que l'on appellera ici fonction). Plutôt que de tout mettre dans une fonction de test, il est judicieux d'en écrire plusieurs pour avoir une meilleure séparation des tests et un meilleur suivi en cas d'échec de l'un d'eux.
Exemple :
class Addition { public int additionner(int a, int b){ return a + b; } } class AdditionTest { private Addition addition; @Before public void setup(){ this.addition = new Addition(); } @Test public void additionnerDeuxPositifs(){ // Test addition deux nombres positifs assertEqual(2, this.addition.additionner(1,1); } @Test public void additionnerDeuxNegatifs(){ // Test addition deux nombres négatifs assertEqual(-2, this.addition.additionner(-1, -1); } @Test public void additionnerPositifEtNegatif(){ // Test addition un nombre négatif et positif assertEqual(0, this.addition.additionner(-1, 1); } }
Maintenant, considérons que je développe 5 tests unitaires par fonction pour une classe qui contient une dizaine de fonction. Cela fait une cinquantaine de tests unitaires dans la même classe. Ne serait-il pas plus judicieux de créer une classe par test de fonction ? Plutôt que d'avoir une classe avec 50 tests unitaires, ne serait-il pas mieux d'avoir 10 classes avec 5 tests unitaires ? Par "mieux", j'entend la maintenance et l'évolutivité du code.
Exemple :
class Operation { public int additionner(int a, int b){ return a + b; } public int soustraire(int a, int b){ return a - b; } } class OperationAdditionnerTest{ private Operation operation; @Before public void setup(){ this.operation = new Operation(); } @Test public void additionnerDeuxPositifs(){ // Test addition deux nombres positifs assertEqual(2, this.addition.additionner(1,1); } @Test public void additionnerDeuxNegatifs(){ // Test addition deux nombres négatifs assertEqual(-2, this.addition.additionner(-1, -1); } @Test public void additionnerPositifEtNegatif(){ // Test addition un nombre négatif et positif assertEqual(0, this.addition.additionner(-1, 1); } } class OperationSoustraireTest{ private Operation operation; @Before public void setup(){ this.operation = new Operation(); } @Test public void soustraireDeuxPositifs(){ // Test soustraction deux nombres positifs assertEqual(0, this.operation.soustraire(1,1); } @Test public void soustraireDeuxNegatifs(){ // Test soustraction deux nombres négatifs assertEqual(0, this.operation.soustraire(-1, -1); } @Test public void soustrairePositifEtNegatif(){ // Test soustraction un nombre négatif et positif assertEqual(-2, this.operation.soustraire(-1, 1); } }
Il y a des inconvénients à faire ça : nom de classe trop long pour les décrire précisément, peut-être problème de performance (car 10 instances de classe plutôt qu'une), des classes parfois trop courtes (si j'écris un test unitaire pour une fonction).
A voir également:
- Doriane vient d’ouvrir un restaurant à lyon. en plus des actions menées sur son site web, elle souhaite développer la visibilité de son restaurant. pour cela, elle peut utiliser différentes techniques.
- Comment ouvrir un fichier epub ? - Guide
- Site de telechargement - Accueil - Outils
- Site pour vendre des objets d'occasion - Guide
- Site pour partager des photos - Guide
- Comment ouvrir un fichier bin ? - Guide
1 réponse
Bonjour,
Je pense que chacun doit voir midi à sa porte, il y a différents "courants de pensées", notamment les puristes qui te diront qu'il faut tout atomiser au plus fin possible, en ce qui me concerne je serais plus pragmatique, les qualités que tu cites "maintenance et l'évolutivité" ne sont pas à négliger, loin de là.
Toutefois, je garderais une seule classe de test par classe de code, parce que lorsque tu utilises des outils d'analyse des résultats de tests, on s'y retrouve plus facilement. Sachant qu'il n'y a pas que des tests unitaires, il y a aussi les tests d'intégrations, moins atomiques mais avec des scénarios plus complexes.
Remarque : dans ton petit code exemple il y aurait déjà bien des choses à améliorer et tester ;-)
Je pense que chacun doit voir midi à sa porte, il y a différents "courants de pensées", notamment les puristes qui te diront qu'il faut tout atomiser au plus fin possible, en ce qui me concerne je serais plus pragmatique, les qualités que tu cites "maintenance et l'évolutivité" ne sont pas à négliger, loin de là.
Toutefois, je garderais une seule classe de test par classe de code, parce que lorsque tu utilises des outils d'analyse des résultats de tests, on s'y retrouve plus facilement. Sachant qu'il n'y a pas que des tests unitaires, il y a aussi les tests d'intégrations, moins atomiques mais avec des scénarios plus complexes.
Remarque : dans ton petit code exemple il y aurait déjà bien des choses à améliorer et tester ;-)
J'aurais voulu avoir une réponse sur l'aspect performance aussi notamment. Mieux vaut créer une classe de 50 méthodes ou 10 classes de 5 méthodes ?
En terme de performance ça ne changera rien, 1 classe de 50 méthodes ou 10 classes de 5 méthodes, ça fera toujours 50 tests à exécuter... Il faut surtout penser à la lisibilité de l'analyse qui en ressort et avoir un rapport par classe de code ça permet de mieux comprendre les résultats.
Exemple d'illustration avec Jenkins :
Exemple d'illustration avec Sonar :
En terme de lisibilité j'aurait donc un test qui plante pour Operation, mais il faudra farfouiller dans le détail pour savoir si c'est un test de OperationTest ou OperationAdditionnerTest qui a planté dans le cas où tu ais les deux.
Et en terme de maintenance, il est plus simple de penser à changer une classe qu'à en changer plusieurs.
Remarque : J'ai déjà eu des problèmes avec des agrégation de rapport Test+IT (sur une version boguée de JaCoCo) et ça aurait sûrement été la même chose avec une agrégation de deux rapports Test d'une même classe, même si ça ne change rien en terme de performance, c'est quand même plus complexe d'avoir plusieurs classes.