Mockito 1.9.0 is out - Bientôt sur les repos maven

par le
Lecture: 7 minutes

EDIT: Hop. Enfin la release 1.9.0 est dispo en téléchargement.


Après pas mal de travail avec des périodes plus ou moins intenses - bref les vicissitudes du développement Open Source - le projet sort une nouvelle version 1.9.0 en Release Candidate, avec des bugfixes et bien sûr des nouvelles features. Il y a un ici et bientôt disponible sur le central maven.

  • Pour être plus fluent et expressif, l’API introduit les alias then() et will() pour les réponses personnalisées (Answer). Ainsi que d’autres petits tweak de l’API:
@Test
public void engine_should_only_work_with_diesel() {
    given(engine.start()).will(throwExceptionIfEssenceInsteadOfDiesel());
    // ...
}

private Answer throwExceptionIfEssenceInsteadOfDiesel() {
    return new Answer<EngineStatus>() {
        public EngineStatus answer(InvocationOnMock invocation) {
            // answer code
        }
    };
}
  • Les mocks peuvent maintenant être déclaré dans la configuration du stub, sur une ligne.
DieselEngine de = given(mock(DieselEngine.class).start()).willThrow(TankIsEmpty.class)
                                                         .getMock();
  • On peut maintenant renvoyer la classe d’une exception plutôt que son instance.
given(someMock).willThrow(IllegalArgumentException.class, SomethingIsWrongException.class);
  • Si jamais vous avez besoin de debugguer un bout de code ou les interactions sont non prédictibles, il est maintenant possible de loguer les invocations du mock ou de l’espion. Attention, bien qu’utile à l’occasion avec du code legacy, quand même si jamais ce besoin s’en fait sentir sur un nouveau développement c’est que ce code devient trop complexe.
List mockedList = mock(List.class, withSettings().verboseLogging());
mockedList.get(0);

On pourra également ajouter des callbacks sur chaque interaction du mock.

Observer observer = mock(Observer.class,
                        withSettings().invocationListeners(listener1, listener2));
willThrow(IllegalArgumentException.class).given(observer.update(observable,
                                                                "what has changed"));
  • Pas mal de travail a été fait sur les annotations. Maintenant il n’est plus nécéssaire d’initialiser un champ annoté par @Spy s’il existe dans la classe un constructeur sans argument.
@RunWith(MockitoJUnitRunner.class)
public class SomeTest {
  // pas besoin d'initialiser le champs
  @Spy private ArrayList spiedArrayList;

  @Test public void verify_some_interactions() {
    spiedArrayList.iterator();
    verify(spiedArrayList, once()).iterator();
  }
}
  • Et pour la fin mais pas des moindres, le mécanisme d’injection de mockito supporte maintenant l’injection par constructeur. A l’heure actuelle, seul les mocks et spies déclaré dans le test en tant que champs pourront être injecté dans le constructeur du champs annoté par @InjectMocks.
@RunWith(MockitoJUnitRunner.class)
public class EngineTest {
  @Mock Diesel diesel;
  @InjectMocks Engine engine;

  @Test public void engine_should_consume_Diesel() {
    engine.start();
  }
}

Ou Engine a un constructeur avec le paramètre Diesel.

public class Engine {
  Diesel diesel;
  public Engine(Diesel diesel) {
    this.diesel = diesel;
  }

  public boolean start() {
    checkNotEmpty(diesel);
    // ...
  }
  // ...
}

Pour l’instant en RC, cette release permettra d’adoucir les angles si nous en avons loupé certains éléments. N’hésitez pas à nous poser des questions sur la stackoverflow.