Nous avons vu dans la partie 1 de l’article comment écrire les tests unitaires sur la construction de la classe Produit et ses méthodes equals et hashcode.
Je vais insister dans un premier temps sur l’amélioration de l’écriture des setup répétitifs des tests.
Je vais utilisé un builder.
Le besoin est ici de simplifier l’écriture des tests, de plus je souhaite garder un minimum de code dans la classe métier, je n’ai donc pas fait le choix d’écrire une classe ProduitBuilder interne à Produit. Au lieu de cela je me base simplement sur un helper de test. ProduitBuilder est donc ajouté dans le package de test.
public class ProduitBuilder { private Produit produit = new Produit(); private static ProduitBuilder produit() { return new ProduitBuilder(); } public ProduitBuilder code(String code) { produit.setCode(code); return this; } public static ProduitBuilder produitAyantCode(String code) { return produit().code(code); } public ProduitBuilder nom(String nom) { produit.setNom(nom); return this; } public ProduitBuilder innovant(boolean innovant) { produit.setInnovant(innovant); return this; } public Produit build() { return produit; } }
Voici également le code que j’ai écris dans ProduitTest correspondant au test de la méthode builder de ProduitBuilder
import static com.devagilestories.ProduitBuilder.produitAyantCode; @Test public void builder() { Produit produit = produitAyantCode("A").nom("builder").innovant(false) .build(); assertEquals("A", produit.getCode()); assertEquals("builder", produit.getNom()); assertFalse(produit.isInnovant()); }
Lorsqu’on refactore l’écriture des tests des méthodes equals et hashcode à l’aide de ProduitBuilder cela donne dans ProduitTest :
//... @Test public void deuxProduitMemeCodeSontEgaux() { assertEquals( produitAyantCode("A").nom("produit top").build(), produitAyantCode("A").nom("produit super").innovant(false) .build()); } @Test public void deuxProduitCodesDifferentsNonEgaux() { assertFalse(produitAyantCode("A").nom("nom produit A").build() .equals(produitAyantCode("B").nom("nom produit A").build())); } @Test public void equalsAuxLimites() { // setup Produit produit = new Produit(); // pre-assert assertTrue(new Produit() {} instanceof Produit); // test&assert assertTrue(produit.equalsAuxLimites(produit)); assertFalse(produit.equalsAuxLimites(null)); assertFalse(produit.equalsAuxLimites(new Produit(){})); assertNull(produitAyantCode("A").build().equalsAuxLimites( produitAyantCode("A").build())); assertNull(produitAyantCode("A").build().equalsAuxLimites( produitAyantCode("B").build())); } @Test public void deuxProduitsEgauxOntMemeHashCode() { // respect du contrat general methode hashcode // pre-assert assertEquals(produitAyantCode("A").build(), produitAyantCode("A") .build()); assertFalse(produitAyantCode("A").build() == produitAyantCode("A") .build()); // assert assertTrue(produitAyantCode("A").build().hashCode() == produitAyantCode("A").build().hashCode()); } @Test public void deuxProduitsDifferentsOntHashCodeDifferents() { // pour des raisons d'optimisation assertFalse(produitAyantCode("A").build().hashCode() == produitAyantCode("B").build().hashCode()); } //...
Pour compléter la deuxième partie de l’article je vais proposer une manière simple de
gérer les dates en java tout en introduisant une nouvelle règle :
on considère que la date de mise en ligne du produit est par défaut de 6 mois après sa création.
J’ajoute à mes dépendances maven la librairie joda-time désormais assez connue comme une excellente alternative à la gestion des dates en java.
<dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>1.6.2</version> </dependency>
J’ajoute le test nouveauProduitEstDispoDans6Mois dans ProduitTest.
@Test public void nouveauProduitEstDispoDans6Mois() { assertEquals(new LocalDate().plusMonths(6), new Produit().getDateMiseEnLigne()); }
Je complète la classe Produit.
private static final int DELAI_MOIS_MISE_LIGNE = 6; private LocalDate dateMiseEnLigne = new LocalDate().plusMonths(DELAI_MOIS_MISE_LIGNE); public LocalDate getDateMiseEnLigne() { return dateMiseEnLigne; } public void setDateMiseEnLigne(LocalDate pDateMiseEnLigne) { this.dateMiseEnLigne = pDateMiseEnLigne; }
Voila, avec joda-time l’ajout d’une date comme attribut dans un objet métier c’est trivial.
Dans cette deuxième partie on a donc vue comment prendre du recul pour améliorer la productivité des tests avant d’aller plus loin dans la conception du modèle.
Dans la partie 3 nous verrons l’ajout de contraintes sur le modèle.