Bonjour,
Cela fait 5 ans que je bosse en Java et seulement 1an que j'ai découvert le réel intérêt de tests unitaires (comme quoi il n'est jamais trop tard).
Je tâtonne encore donc avec les bonnes pratiques et je tombe de façon récurrente sur un problème de design.
Prenons l'exemple d'un morceau de programme qui converti des objets d'un framework dans un autre.
Modèle librairie 1
Modèle librairie 2
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 public class Panier { private Collection<Fruit> fruits; // getters, setters, equals, hashCode, ... ... } public class Fruit { private String nom; // getters, setters, equals, hashCode, ... ... }
Pour convertir des objets d'une librairie dans l'autre, j'étais tenté d'écrire une seule classe qui faisait le boulot :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 public class Basket { private Map<Integer, JuicyFruit> juicyFruits; // getters, setters, equals, hashCode, ... } public class JuicyFruit { private String name; // getters, setters, equals, hashCode, ... }
Le problème avec la classe ci dessus c'est que l'écriture des tests unitaires peut très vite devenir fastidieuse à cause de l'appel en cascade des méthode "convert". Convertir un "Panier" oblige à passer des objet "Fruits" valide sous peine de générer des erreurs indésirables et la construction de tous ces objets peut vite rendre le test illisible / pas maintenable.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 public class ObjectsConverter { public Basket convert(Panier panier) { Basket basket = ... // logique plus ou moins complexe for (Fruit fruit : panier.getFruits()) { basket.add(this.convert(fruit)); } return basket; } public JuicyFruit convert(Fruit fruit) { JuicyFruit jFruit = ... // logique plus ou moins complexe return jFruit; } }
La solution que j'ai trouvée jusqu'à présent est de créer 2 classes séparées qui convertissent chacune un des objet (1 convertisseur de "Panier" et un convertisseur de "Fruit")
En utilisant l'inversion de contrôle, des interfaces et des mocks, les tests unitaires redeviennent simples.
Seulement cette technique m'embête car elle est prompte à créer des dizaines de classes et interfaces ne contenant qu'une seule pauvre méthode qu'on peine à nommer de façon appropriée. Et du coup c'est l'API qu'on crée qui devient touffue et difficile à utiliser.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 public class PanierConverter { private FruitConverter fruitConverter; public Basket convert(Panier panier) { Basket basket = ... // logique plus ou moins complexe for (Fruit fruit : panier.getFruits()) { basket.add(this.fruitConverter.convert(fruit)); } return basket; } } public class FruitConverter { public JuicyFruit convert(Fruit fruit) { JuicyFruit jFruit = ... // logique plus ou moins complexe return jFruit; } }
On peut évidemment utiliser un pattern façade pour re-simplifier l'API mais ça ressemble au tapis sous lequel on cache la poussière.
Je me demandais donc comment d'autres professionnels adressent cette problématique.
D'avance merci pour vos réponses.
Partager