Nous démarrons avec un projet exemple simple qui permet de comprendre les notions importantes dans EasyMock.
1- Le projet exemple:
Comme notre objectif est de faire du TDD, nous allons écrire uniquement les interfaces puis enchaîner avec les tests sur des classes simulées (moquées) par EasyMock.
/***interface couche dao**/ public IContactDao{ void save(Contact contact) ; }
Et celle de service:
/***interface couche service*****/ public IService{ void save(Contact contact) ; void setContactDao(IDao dao); }
Et l'entité Contact est un POJO simple:
package fr.netapsys.easymock.entites; import java.io.Serializable; import fr.netapsys.easymock.common.BaseObject; public class Contact implements Serializable { private static final long serialVersionUID = -1511337412528984583L; private int id; private String nom; private String prenom; private String mail; public Contact() { super(); } //Setters/getters omis }
Donc nous avons en place les briques techniques qui vont servir à pratiquer le TDD et favoriser les échanges avec le client.
Écrivons les tests avant de commencer les développement pur et dur des couches dao, service et web(back & front).
La classe de test est simple néanmoins consistante afin d'illustrer réellement l'apport des test mock.
2- Classe JUnit4 test
package fr.netapsys.easymock.tests; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import fr.netapsys.easymock.entites.Contact; import fr.netapsys.easymock.interfaces.*; //**** notez cet import ***** import static org.easymock.EasyMock.*; @RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (locations = { "classpath:spring.xml" }) public class TestEasyMock { private final Logger logger=Logger.getLogger(getClass()); private IContactDao contactDao; private IContactService contactService; @Before public void setUp() { contactDao=createMock(IContactDao.class); contactService= createMock(IContactService.class); } @SuppressWarnings("nls") @Test public void testSave() { Contact contact=new Contact(); //************** createMock, expect, replay, call & verify expect(contactDao.save(contact)).andReturn(saveContactInDao(contact)); replay(contactDao); contactDao.save(contact); verify(contactDao); //appel au service expect(contactService.save(contact)).andReturn(saveContactInService(contact)); replay(contactService); Contact c=contactService.save(contact); logger.info(">>>>Contact retrieved by service :"+contact.toString()); verify(contactService); Assert.assertTrue( c.getNom().equals(contact.getNom()) && c.getId()==1 && c.getMail().equals("mail@mail.fr")); } @SuppressWarnings("nls") private Contact saveContactInDao(Contact contact) { Contact contact2Return=contact; contact.setNom("Easymock"); contact.setPrenom("test"); //setter id contact2Return.setId(1); return contact2Return; } @SuppressWarnings("nls") private Contact saveContactInService(Contact contact) { Contact contact2Return=contact;//contactDao.save(contact); contact2Return.setMail("mail@mail.fr"); return contact2Return; } }
NB. Le fichier spring.xml est pour l'instant vide. Il ne contient que les déclarations des namespaces.
La seconde partie de ce billet revient sur ce fichier de configuration pour aller plus loin dans l'utilisation de l'api easymock combiné avec spring.
3- Exécutions des tests
La première capture illustre que le test JUnit répond bien:
Avec une sortie sur la console qui ressemble à:
[INFO (TestEasyMock.java) >>>>Contact retrieved by service :fr.netapsys.easymock.entites.Contact@17050f5[ id=1 nom=Easymock prenom=test mail=mail@mail.fr ]]}
Easymock est utilisé par spring et le projet apache strutstestcase. Néanmoins, à mon avis, il est plus ou moins intuitif à pratiquer.
Son concurrent MOCKITO séduit par la simplicité d'emploi.
EasyMock se comporte comme un "recorder" et par conséquent nécessite généralement les étapes suivantes:
createMock, ( C'est ce que a été fait dans la méthode annotée par @Before )
expect, (C'est ce qui a été fait dans le corps de la méthode testSave)
replay, (idem)
call, (idem)
verify. (idem. A noter que cet appel peut générer une exception incompréhensible si l'ordre des étapes n'est pas respecté)
La prochaine fois, nous introduirons l'auto-injection Spring des beans de la couche service en simulant (en moquant) uniquement la couche DAO.
Commentaires