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.

Publicités