insideIT.fr : le blog des architectes IT de SFEIR

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 23 juin 2011

La marmite des Duchess

La 1ère édition de la Marmite des Duchess a eu le 7 juin dernier. Nom de code "Crumble".
Ce nouvel évènement, proposait 2 sessions en parallèle, le choix se faisait à l'inscription :
- Atelier Mockito, animé par Mathilde Lemée et David Gageot. (limité à 20 places)
- Open Space Technologique. (limité à 40 places)
Doit on y voir l'anologie du crumble dans ce découpage ? Je ne saurais répondre à cette question.

Au total, une trentaine de personnes (dont 6 Sfeirien(ne)s) étaient présentes pour une durée d'un peu plus de 2 heures.

Atelier Mockito





C'est la partie à laquelle j'ai assisté.
Cet atelier était basé sur le code de tudu-list. Le but était de, en peer programming, compléter des tests et de les faire passer au vert. Pour palier aux différentes connaissances et niveaux des participants, les tests étaient répartis en 3 niveaux de difficulté.
Pour ma part, connaissant un peu Mockito, j'ai affronté le niveau 2. Nos animateurs étaient bien sûr présent pour nos différentes questions sur la façon de développer/organiser nos tests aussi bien sur Mockito mais aussi sur FestAssert.
Ces exercices permettent d'avoir quelques bases sur Mockito en découvrant sa syntaxe et ses particularités mais aussi si nous sommes rigoureux de se familiariser avec le formalisme BDD,  conseillé pour bien se concentrer sur une seule chose à tester par méthode de test.

Si vous souhaitez tenter le défi, le code à compléter est ici et la solution .

Open Space Technologie




D'après ce que j'en ai compris, un open space technologie est assez semblable à un bar camp, mis à part qu'il n'y a pas de sessions parallèles.
N'ayant pas de don d'ubiquité, je n'étais pas présent à cette partie. Mais heureusement, mon collègue Clément Griffoin avait pris des notes.


Différents sujets ont étés abordés dont :
- Women in java
- ForPlay où Pierre-Yves Ricau fera une démonstration de sa réalisation
- Déploiement continu
- Stubs vs Mock
- TDD/DDD/BDD


Vous pourrez retrouver plus d'informations ce qui s'est dit dans cette partie sur le blog des Duchess.

Et pour finir, c'est un autour d'un repas que les derniers motivés se sont retrouvés.


Merci et félicitations pour cette première édition ! Et vivement la suite à la rentrée.

Des photos de cet article ainsi que toutes les photos la soirées sont disponible sur l'espace Flickr de Duchess France

mardi 1 mars 2011

Retour d'expérience d'un projet GWT : 6 Ecrire des tests unitaires avec Mockito (6/8)

Le contexte:

Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR

Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.

Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech

  1. Nouveautés de GWT 2.0
  2. UiBinder, enfin une forte collaboration entre le designer et le développeur
  3. Intégration facile de maquette Html en GWT 2
  4. Architecture Modèle-Vue-Presenteur
  5. Implémentation Modèle-Vue-Présenteur
  6. Ecrire des tests unitaires avec Mockito
  7. Mise en place de Gin sur le projet
  8. Internationalisation

Tester une application GWT avec une architecture MVP permet de pouvoir écrire des tests JUnit en java pure sans utiliser l'implémentation GWT de JUnit qui démarre un serveur web et un navigateur pour lancer les tests unitaires. Ce qui prend du temps si l'on doit exécuter ses tests à chaque modification de l'application.

Pour qu'il soit possible d'écrire des tests en Java pure, il faut que le Présenter ne possède aucune référence à des classes du package Ui de GWT. C'est à dire toutes les classes qui étendent Widget et qui permettent d'afficher des informations, ce qui logiquement doivent être définie dans la vue. Il faut ainsi écrire un contrat entre le présenteur et la vue sous la forme d'une interface Display. Ce contrat ne doit posséder que des paramètres et valeurs de retour définie par une interface ou pouvant être utiliser par Java (pas de TextBox getLogin() mais un HasValues<String> getLogin() ou toute autre classe faisant référence à des Widget GWT)

De même, il n'est pas possible d'utiliser GWT.create() autrement dit, pour instancier les services RPC, les classes de Constantes pour l'internationalisation, etc ...

Il est donc nécessaire de faire ses instanciations en dehors du Presenter, et ne prendre en paramètre que l'interface de ceux-ci. Il deviens ainsi possible de créer une version spécifique pour les tests, en règle générale, on va écrire des classes qui implémentent les interfaces avec du code minimal pour réaliser nos tests (getter, setter, hash maps pour enregistrer les données, calcule simple ...). Ces classes doivent être maintenue lors que l'on modifie l'application, et peuvent avoir des bugs qui empêche le test de fonctionner correctement.

C'est là que Mockito prend toute sa puissance, en implémentant automatiquement ses interfaces et en ajoutant le comportement de ceux-ci.

Il faut ajouter la dépendance à Mockito à Maven :

     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.8.1</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-all</artifactId>
         <version>1.8.5</version>
         <scope>test</scope>
     </dependency>

Les tests doivent être écrit avec JUnit 4 et être exécutés par le Runner spécifique de Mockito (si on veux utiliser les annotations automatique permettant de créer les mock et les arguments captor)


Mockito

Mockito est un générateur automatique de doublures. Il fonctionne sur le mode de l'espion :

  • On crée les mocks;
  • On décrit leur comportement
  • Ensuite, à l'exécution, toutes les interactions avec les mocks sont mémorisés ;
  • à la fin du test, on interroge les mocks pour savoir comment ils ont étés utilisés.

Toutes les méthodes de mockito sont des méthodes static de la classe Mockito, il est donc nécessaire d'importer statiquement ses méthodes pour simplifier l'écriture :

import static org.mockito.Mockito.*;

On crée un mock soit avec la méthode mock :

MonInterface mock = mock(MonInterface.class);

soit en utilisant l’annotation @Mock:

@Mock
MonInterface mock;

Il n'est pas nécessaire que MonInterface soit une interface, il est possible de mocker une classe (mock(Widget.class) permet d'utiliser une classe GWT dans le test dans que cela pose de problème, une version vide ayant les mêmes méthodes publique est créé par mockito)

On décrit ensuite le comportement attendu de notre mock :

when(mock.maMethode()).thenReturn(42);

On appelle les tests, qui font des interactions avec notre mock, et enfin on vérifie ses interactions

verify(mock).maMethode();

Cette dernière ligne vérifie que la méthode maMethode() a bien été appelé durant le test.


Définir le comportement d'un mock

Pour définir, le comportement d'un mock, on utilise when() auquel on passe en paramètre l'appel que l'on veux définir, c'est à dire l'appel de la méthode avec les paramètres que l'on doit répondre :

interface Add {
    public int add(int a, int b);
}

Si on veux émuler le comportement de notre méthode add qui additionne les deux paramètres, on va donner les résultats pour des paramètres données :

Add mockAdd = mock(Add.class);
when(mockAdd.add(1, 1)).thenReturn(2);
when(mockAdd.add(5, 7)).thenReturn(12);

Ainsi si dans notre test, on appelle mock.add(1, 1), le retour sera 2.

On peux donner plusieurs valeurs de retour qui seront retourné dans l'ordre :

Par exemple, si on veux simulé les retours de la methode random, on fera :

when(randMock.random()).thenReturn(5, 18, 86, 42);

Ainsi le premier appel de random() retournera 5, et le quatrième appel retournera 42 (ainsi que tous les suivants).

On peux aussi simuler l'envoie d'une exception avec la method thenTrow() :

when(mock.div(anyIn(),0)).thenTrow(new Exception("Division par zéro));

Qui lancera alors une exception lors que le deuxième paramètre est un zéro.


Vérifier les appels aux mock

La méthode verify() qui prend en parametre permet de vérifier qu'une méthode à bien été appeler :

verify(mock).mustCall(1)

Cette ligne permet de vérifier que la méthode mustCall a bien été appelé lors du test, et de plus permet de vérifier que le paramètre est bien 1.

On peux tester le nombre de fois où la methode a été appellé :

verify(mock, times(5)).add(anyString());

On vérifie ici que la méthode add a été appellé 5 fois avec une chaînes de caractères en paramètre.

Si on veux tester plus de choses sur les arguments, il est possible de les capter (les enregistrer) pour ainsi faire des tests plus poussé dessus :

ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(userservice).login(captor.capture());
assertEquals("login", captor.getValue().getLogin());

On peux aussi vérifier qu'il n'y a pas eu d'interaction avec un mock

verifyZeroInteractions(mock);


Utilisation avec GWT

Si on veux tester qu'un événements a bien été envoyé par GWT, on utilise les mock et les ArgumentCaptor :

@Captor
ArgumentCaptor<ValueChangeEvent<String>> valueChangeEventCaptor;

@Mock
ValueChangeEventHandler<String> handler;

@Test
void testValueChangeEventHandler() {
    TestClassWithValueChangeHandlers test = new TestClassWithValueChangeHandlers();
    //On s'enregistre dans l'eventBus à l'évènement click
    test.addValueChangeHandler(handler);
    //On appelle la methode à tester qui envois notre évènement ValueChange();
    test.setValue("newValue");
    //On vérifie que celui-ci a bien été appellé
    verify(handler).onValueChange(valueChangeEventCaptor.capture());
    //On test que la nouvelle valeur est bien danc l'object event :
    assertEquals("newValue",             valueChangeEventCaptor.getValue().getValue());
}

Références Documentation de Mockito