Lors de l’écriture de tests unitaires, on peut se retrouver à écrire ce genre de code :

assertEquals(42, answer);
assertFalse(answer == 34);
assertTrue(info.matches("color") || info.matches("colour"));
assertTrue(colorsList.contains("red"));
assertTrue(s instanceof MagicString);

Mais JUnit propose depuis la version 4.4 une nouvelle syntaxe à base de Matchers. En fait, cette syntaxe n’est pas totalement nouvelle : elle est empruntée à JMock qui possède déjà les Matchers JMock pour décrire les contraintes d’un mock. L’idée vient de Joe Walnes dans son article Flexible JUnit assertions with assertThat().

Les assertions précédentes peuvent alors s’écrire de la manière suivante :

assertThat(answer, is(42));
assertThat(answer, is(not(34)));
assertThat(info, either(containsString("color")).or(containsString("colour")));
assertThat(colorsList, hasItem("red"));
assertThat(s, instanceOf(MagicString.class));

Les avantages sont multiples :

  • Ça se lit mieux : le développeur communique donc mieux son intention aux autres développeurs, ce qui est essentiel !
  • Contrairement aux méthodes assertEquals et consorts, on ne risque pas de tromper dans l’ordre des arguments : la syntaxe d’assertEquals est assertEquals([expected], [actual]) mais beaucoup de gens se trompent et écrivent assertEquals(answer, 42). Avec assertThat, aucun risque.
  • Les matchers peuvent être modifiés: par exemple : not(s) pour inverser la condition, either(s).or(t) pour combiner des conditions, each(s) pour appliquer une condition sur chaque élément d’une collection, afterFiveSeconds(s) pour attendre 5 secondes avant de tester…
  • En cas d’échec de l’assertion, les messages sont beaucoup plus lisibles. Si on reprend l’exemple précédents, avec les assertXxx classiques, les messages ressembleraient à ça :
    assertEquals(42, answer);
     => expected:<42> but was:<36>
    assertFalse(answer == 34);
     => junit.framework.AssertionFailedError:
    assertTrue(info.matches("color") || info.matches("colour"));
     => junit.framework.AssertionFailedError:
    assertTrue(colorsList.contains("red"));
     => junit.framework.AssertionFailedError:
    assertTrue(s instanceof MagicString);
     => junit.framework.AssertionFailedError:
    

    Avec assertThat, les message ressemblent plutôt à ça :

    assertThat(answer, is(42));
     => Expected: is <42>
             got: <36>
    assertThat(answer, is(not(34)));
     => Expected: is not <34>
             got: <34>
    assertThat(info, either(containsString("color")).or(containsString("colour")));
     => Expected: (a string containing "colour" or a string containing "color")
             got: "rainbow"
    assertThat(colorsList, hasItem("red"));
     => Expected: a collection containing "hello"
             got: <[bonjour, ia orana]>
    assertThat(s, instanceOf(MagicString.class));
     => Expected: an instance of sandbox.FooTest$MagicString
             got: "polop"
    

    Inutile de dire qu’il est beaucoup plus facile de débugguer des tests écrits avec assertThat…

  • Il est plus facile d’écrire des Matcher maison plutôt que des méthodes assertXxxx maison. En plus ces Matchers pourront être réutilisés dans des tests JMock.
  • C’est sexy :)

Pour plus d’informations, je vous recommande la lecture de ce billet. Il est en français, il est très détaillé et je suis tombé dessus en écrivant cet article.

sponsor-sida
Ça y est, le pape a déclaré être contre le préservatif. Ce n’est pas neuf, mais apparemment, c’est la première fois qu’il prononce le mot préservatif…

L’église a des arguments pour justifier la position du pape. Dommage ces arguments ne sont applicables qu’aux 20% d’africains de religion catholique. Pour 580 millions restants, il y a fort à parier que proposer l’abstinence comme moyen de lutte contre la propagation du VIH Africains n’est pas au goût du jour.