Étendez les fonctionnalités de Mockito grâce à PowerMock

powermock_logo.png

Écrire des tests unitaires peut être difficile et parfois, un bon design doit être sacrifié par soucis de testabilité. Une application bien construite doit être facilement testable, mais il arrive que ce ne soit pas toujours le cas. Par exemple les classes finales et les méthodes finales ou statiques ne peuvent pas être mockées, les méthodes privées doivent être passées en protected, du fait des limitations des frameworks de tests actuels tels que Mockito et EasyMock.

C'est là qu'intervient PowerMock.

PowerMock est un framework qui étend les fonctionnalités d’autres APIs de tests telles que Mockito et EasyMock. Il utilise un classloader personnalisé et manipule le bytecode permettant ainsi de mocker des méthodes statiques, des constructeurs, des classes et des méthodes finales, de supprimer les initialisateurs static, et bien plus.

Dans cet article, je montrerai comment :

  • Mocker une méthode finale
  • Mocker une méthode statique
  • Mocker une méthode privée
  • Tester une méthode privée

Les exemples seront basés sur une version de PowerMock qui étend Mockito (PowerMockito).

Installation

PowerMock étend les fonctionnalités de Mockito et d'EasyMock, donc il faut que l'une de ces librairies soit installée.

Pour les utilisateurs de Maven, l'installation se fait simplement en ajoutant une dépendance au pom.xml. La dépendance à ajouter varie en fonction de l'API de tests utilisée :

  • Pour les utilisateurs de Mockito : voir ici
  • Pour les utilisateurs d'EasyMock : voir ici

Exemples d'utilisation

Soit les classes suivantes qui gèrent des entités de type Personne :

PersonneService__Factory.png

Cette classe est difficilement testable unitairement. En effet, on peut remarquer l'utilisation de méthodes statiques, finales et privées. Si on utilise Mockito, les solutions sont les suivantes :

  • modifier le code source afin qu'il soit plus facilement testable
  • ne pas tout tester unitairement
  • utiliser PowerMock

C'est la dernière solution que nous choisissons.

Avant toute chose, il est nécessaire d'utiliser le runner de PowerMock, en indiquant ce qui suit au dessus de la déclaration de la classe :

@RunWith(PowerMockRunner.class)

Ensuite, chaque classe utilisée par PowerMock doit être déclarée, en début de classe, via l'annotation @PrepareForTest. Exemple :

@PrepareForTest({DateTime.class, PersonneFactory.class})

Mocker une méthode finale

Le premier test unitaire concerne la méthode newPersonne(), de la classe PersonneService. Celle-ci prend en paramètre une date de naissance et nous renvoie un objet de type Personne initialisé. Cette méthode utilise la méthode create() de la classe PersonneFactory.
Nous ne voulons pas tester cette dernière (on teste unitairement). Nous voulons tester que la méthode create() est appelée et que l'objet qu'elle retourne est retourné par la méthode newPersonne(). Il faut donc mocker la méthode create(). Celle-ci étant finale, il n'est pas possible de le faire avec Mockito. Nous le faisons donc avec PowerMock.

Tout d'abord, ajouter @PrepareForTest(PersonneFactory.class) en début de classe.
Ensuite utiliser la méthode PowerMockito.mock() pour mocker la classe PersonneFactory. On obtient un test qui ressemble à ceci :

testNewPersonne.png

Mocker une méthode statique

Pour tester la méthode getAge() de la classe PersonneService, nous devons pouvoir mocker une méthode statique. En effet, elle nécessite la date du jour, qui est calculée par la méthode statique DateTime.now(). Mockito ne permet pas cela.
Nous ajoutons donc @PrepareForTest(DateTime.class) en début de classe.
Puis nous mockons les méthodes statiques de la classe DateTime à l'aide de la méthode PowerMockito.mockStatic(). Nous obtenons ainsi le test suivant :

testGetAge.png

Tester une méthode privée

Nous voulons ensuite tester la méthode privée isMajeur(). Sans PowerMock, nous serions obligés de changer sa visibilité à "protected".
PowerMock fournit la classe Whitebox qui permet d'appeler par introspection des méthode privées. On obtient alors :
testIsMajeur.png

Mocker une méthode privée

Enfin, nous testons la méthode peutVoterEnFrance(). Celle-ci se utilise sur la méthode privée isMajeur(). Nous testons unitairement, donc nous voulons mocker cette dernière, ce qui ne serait pas possible sans PowerMock vu qu'elle est privée. Voici ce que nous obtenons :

testPeutVoter.png

Nous ajoutons donc @PrepareForTest(PersonneService.class) en début de classe.
Nous mockons la méthode isMajeur() avec PowerMockito.spy() au lieu de Mockito.spy(), puis mockons son comportement.
Nous vérifions que la méthode est bien appelée, avec PowerMockito.verifyPrivate().

NB : on utilise spy() car la méthode isMajeur() fait partie de la classe testée, sinon nous aurions utilisé mock().

Conclusion

Je vous ai montré quelques exemples d'utilisation. Néanmoins, PowerMock permet de réaliser bien d'autres choses comme de mocker des constructeurs, de supprimer les initialisateurs static... Pour plus d'informations, une seule adresse : https://code.google.com/p/powermock

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.