Comment tester unitairement du code asynchrone en Java
Je m’essaye à quelque chose d’un peu différent de ce que j’écris habituellement : la présentation d’un outil qui m’a été utile. N’hésitez pas à me dire si ce type d’article vous intéresse également !
Tous ceux qui ont eu le plaisir de tester unitairement des opérations asynchrone en java savent que cela se transforme souvent en cauchemars.
Le problème est de réussir à cadencer correctement les différentes parties du code, et attendre que les opérations asynchrones aient bien été réalisées pour pouvoir lancer les assertions.
C’est souvent l’occasion de voir des bricolages très inventifs, souvent à l’aide de callbacks
, flags
et autres Thread.sleep()
. Avec le risque d’avoir des tests fragiles qui se retrouvent bloqués dans leur exécution.
var result = somethingAsync();
Thread.sleep(100);
assertThat(result).isEqualTo(...);
io.vertx.core.Future<?> future = somethingAsync();
while(!future.isComplete()) {
Thread.sleep(10);
}
assertThat(future.result()).isEqualTo(...);
Awaitility à la rescousse
En cherchant comment améliorer le test unitaire d’une fonction asynchrone, je suis tombé sur un outil très sympathique dédié à ce cas d’usage : awaitility.
Grâce à lui nous pouvons réécrire le test précédent avec de manière beaucoup plus agréable :
var future = somethingAsync();
await().pollInterval(10, TimeUnit.MILLISECONDS) //try every 10ms
.atMost(50, TimeUnit.MILLISECONDS) //timeout after 50ms
.until(future::isComplete);
assertThat(future.result()).isEqualTo(...);
Le DSL est très simple mais suffisamment bien pensé pour pouvoir s’adapter à plein de situations. Par exemple, si vous avez besoin d’attendre un effet de bord asynchrone.
await().pollDelay(10, TimeUnit.MILLISECONDS) //wait 10ms before first try
.atMost(50, TimeUnit.MILLISECONDS) //timeout after 50ms
.until(() -> persistence.exists("someId"));
Pour être tenu au courant des prochains articles ou conférences, vous pouvez les recevoir par mail. Et si vous avez apprécié cet article, c'est l'occasion de le partager sur twitter, Linkedin, ou sur Slack.