Donc pour résumer :

  • EasyMock pour tester le découplage intercouche par les Façades
  • EasyMock-ext pour tester vos objets intra couche par l'implémentation.

Les Mocks sont très utiles mais aussi très contraignent lorsque la complexité de l'implémentation à tester est élevée.

Donc parfois, il reste utile d'implémenter des tests sans se moquer, mais en privilégiant l'utilisation de base de donnée light pour injecter les données et faire les testes sur cette base sans mock.
Voir pour les services, SOAPUI permet de mocker des webServices.

Voici des exemples d'implémentations de Mock avec EasyMock en Java. (Petit rappel tous le code réalisé est fais en mode TDD)

Pour plus de détails, vous pouvez télécharger le projet au format éclipse M2.

Exemple de cas :

Anticipation d'une API non développée :
Deux moyens soit par un Fake ou par un Mock :

// Utilisation d'un Fake, dans le cadre de l'utilisation d'une ressource inexistante interne à la couche

public class OffreEmploiDaoTest {
      OffreEmploiDao offreEmploiDao;


/*Utilisation du Fake, pas très pratique, car nous devrons
 gerer le débranchement du Fake mais aussi la suppression
 du Fake devenu inutile.*/


@Test%%%
public void getAllOffresByFake(){
      offreEmploiDao = new OffreEmploiDaoFake();
      List<offreemploi> offresEmploi = offreEmploiDao.getAllOffresEmploi();
      assertNotNull(offresEmploi);
      assertEquals(4,offresEmploi.size());
}

// Exemple simple de mock d'une interface, tous tiens dans le test. Seul le test sera à refactorer quand l'API sera livrée.

@Test%%%
public void getAllOffresByMock(){
// creation du Mock
      OffreEmploiDao offreEmploiDaoMockDao = EasyMock.createMock(OffreEmploiDao.class);
// création du retour que l'on attend, informations données par soit par
// les spec ou le développeur en charge de la future API.
      List<offreemploi> offresEmploi = new ArrayList<offreemploi>(1);
      offresEmploi.add(new OffreEmploi(1));
//branchement du Mock
      EasyMock.expect(offreEmploiDaoMockDao.getAllOffresEmploi()).andReturn(offresEmploi);
      offreEmploiDao = offreEmploiDaoMockDao;
// cela me fais penser à mon vieux magneto, faut faire play pour activer le mock.
      EasyMock.replay(offreEmploiDaoMockDao);
// Enfin je test
      List<offreemploi> resuktats = offreEmploiDao.getAllOffresEmploi();
      assertNotNull(resuktats);
      assertEquals(1,resuktats.size());
      }
}



Le Principe de découplage architectural :

Lors que vous faites le design d'une architecture en couches, il faut garder en tête que chaque couche ne doit communiquer qu'avec ses couches contigües. De plus, vos tests doivent pouvoir fonctionner unitairement même privés des autres couches.

Dans ce cadre, le découplage doit être votre objectif, afin d'éviter tous problème d'interdépendance cyclique.

Pour ce faire, vous pouver utiliser EasyMock :

Test :

       ///Ici nous pouvons faire l'exemple de découplage entre la couche
       Métier et la couche DAO. Plus question de Fake mais de réaliser un
      design parfait avec un découplage des couches Forte. 
Les mocks sont le meilleur moyen de réaliser un bon découplage.
Le Principe fondamentale de test de votre couche et de ne pas dépendre des autres couche pour réaliser vos tests.
Pourquoi ?
Reponse : Simple, chaque implementation doit être tester dans sa propre couche,
Donc avec ce principe nous ne devons pas retester les resultats des autres couches.///

public class RechercheOffreEmploiBSTest {

     RechercheOffreEmploiBS rechercheOffreEmploiBS;

"Principe de découplage."
"Ici on test notre couche métier."
"Donc nous ne devons pas faire appel à notre couche DAO."

@Test
public void rechercherLesOffresParCompetence() { // Je suis dans la couche metier, j'implemente donc mon interface.

     rechercheOffreEmploiBS = new RechercheOffreEmploiBSImpl();

// Mon critere de recherche

     String competenceRecherchee = "Java";

// Mon Metier a besoin d'utiliser la base donc la couche DAO pour recuperer les offres. // Nous allons donc découpler le business en ajoutant un mock du DAO // pour se concentrer uniquement sur l'implementation de notre metier.
// 1. creation du Mock

     OffreEmploiDao offreEmploiDaoMock = EasyMock

.createMock(OffreEmploiDao.class);
// création du retour que l'on attend.

     List<offreemploi> offresEmploi = new ArrayList<offreemploi>(1);
     OffreEmploi offreJava = new OffreEmploi(1);
     offreJava.getListeCompetences().add(new Competence("Java"));
     offreJava.getListeCompetences().add(new Competence("Cobol"));
     offresEmploi.add(offreJava);
     OffreEmploi offrePython = new OffreEmploi(2);
     offrePython.getListeCompetences().add(new Competence("Python"));
     offrePython.getListeCompetences().add(new Competence("GWT"));
     offresEmploi.add(offrePython);
     OffreEmploi offreRuby = new OffreEmploi(3);
     offreRuby.getListeCompetences().add(new Competence("Ruby"));
     offresEmploi.add(offreRuby);
     OffreEmploi offreJava2 = new OffreEmploi(1);
     offreJava2.getListeCompetences().add(new Competence("  javA  "));
     offresEmploi.add(offreJava2);

// branchement du Mock

     EasyMock.expect(offreEmploiDaoMock.getAllOffresEmploi()).andReturn(

offresEmploi);

     ((RechercheOffreEmploiBSImpl) rechercheOffreEmploiBS)

.setOffreEmploiDao(offreEmploiDaoMock); // cela me fais penser à mon vieux magneto, faut faire play pour activer // le mock.

     EasyMock.replay(offreEmploiDaoMock);
     List<offreemploi> resultatsRecherche = rechercheOffreEmploiBS

.rechercherLesOffresParCompetence(competenceRecherchee);

     assertEquals(2, resultatsRecherche.size());

// code tres tres peut orthodoxe mais j'aime bien, cela fait un peu // kitch, je suis concient de ce la suite du code, cela n'est vraiment // pas un exemple à suivre. // !o)

     boucleEmploi: for (OffreEmploi offreEmploi : resultatsRecherche) {
           List<competence> listeCompetences = offreEmploi
           .getListeCompetences();
           for (Competence competences : listeCompetences) {
                 if (competences.getNom().trim().equalsIgnoreCase(
                 competenceRecherchee)) {
                       continue boucleEmploi;
                 }
           }
           fail();
     }

// enfin on s'assure que le moke à bien fonctionné

     EasyMock.verify(offreEmploiDaoMock);

} }

Implementation :

public class RechercheOffreEmploiBSImpl implements RechercheOffreEmploiBS { // utilisation de la couche DAO private OffreEmploiDao offreEmploiDao;

//Mon metier

public List<OffreEmploi> rechercherLesOffresParCompetence( String competenceRecherchee) { List<OffreEmploi> resultatRecherche = new ArrayList<OffreEmploi>();

// recuperation des offres en base, biensur les getAll sont à banir de // votre code, mais là je réalise un test simple. List<OffreEmploi> allOffresEmploi = offreEmploiDao.getAllOffresEmploi();

// filtrage des offres et création du resultat for (OffreEmploi offreEmploi : allOffresEmploi) { List<Competence> listeCompetences = offreEmploi .getListeCompetences(); if (isOffreEmploiValide(competenceRecherchee, listeCompetences)) { resultatRecherche.add(offreEmploi); } } return resultatRecherche; }

//Methode Helper du Metier, testée à travers rechercherLesOffresParCompetence.
//Voir couverture de code par le plugin covertura dans Maven (ceci est aussi un autre sujet) private boolean isOffreEmploiValide(String competenceRecherchee, List<Competence> listeCompetences) { for (Competence competence : listeCompetences) { if (competence.getNom().trim().equalsIgnoreCase( competenceRecherchee)) { return true; } } return false; }

// Accesseur pour injecter le dao(exemple via spring, c'est un autre sujet)

public void setOffreEmploiDao(OffreEmploiDao offreEmploiDao) { this.offreEmploiDao = offreEmploiDao; } }

Voila pour ce petit exemple d'implémentation d'EasyMock, vous pourrez trouver d'autres exemple sur google !op.

Yannick.