web-dev-qa-db-fra.com

Utilisation de Mockito pour simuler une variable locale d'une méthode

J'ai une classe A qui doit être testée. Voici la définition de A:

public class A {
    public void methodOne(int argument) {
        //some operations
        methodTwo(int argument);
        //some operations
    }

    private void methodTwo(int argument) {
        DateTime dateTime = new DateTime();
        //use dateTime to perform some operations
    }
}

Et en fonction de la valeur dateTime, certaines données doivent être manipulées, récupérées de la base de données. Pour cette base de données, les valeurs sont conservées via un fichier JSON.

Cela complique les choses. Ce dont j'ai besoin, c'est de définir le dateTime à une date spécifique pendant qu'il est testé. Existe-t-il un moyen de se moquer de la valeur d'une variable locale en utilisant mockito?

28
user657592

Vous ne pouvez pas vous moquer d'une variable locale. Cependant, vous pouvez extraire sa création dans une méthode protected et spy:

public class A {
  public void methodOne(int argument) {
    //some operations
    methodTwo(int argument);
    //some operations
  }

  private void methodTwo(int argument) {
    DateTime dateTime = createDateTime();
    //use dateTime to perform some operations
  }

  protected DateTime createDateTime() {
    return new DateTime();
  }
}

public class ATest {
  @Test
  public void testMethodOne() {
    DateTime dt = new DateTime (/* some known parameters... */);
    A a = Mockito.spy(new A());
    doReturn(dt).when(a).createDateTime();
    int arg = 0; // Or some meaningful value...
    a.methodOne(arg);
    // assert the result
}
31
Mureinik

La meilleure façon de traiter un tel problème est d'utiliser un service Clock injecté, utilisé pour obtenir de nouvelles instances de DateTime. De cette façon, votre test peut injecter une horloge factice, qui renvoie un DateTime spécifique au lieu de l'heure actuelle.

Notez que la nouvelle API Java 8 time définit un tel classe Clock , spécifiquement à cet effet.

2
JB Nizet

Désolé pour la réponse tardive.

Cela peut être trop compliqué, mais si vous vous moquez de l'objet qui peut vous donner la variable locale, vous pouvez en renvoyer une maquette. Je préfère ne pas restructurer le code pour faciliter les tests, mais c'est quelque chose à considérer.

public class A {

    DateTimeFactory factory;

    private void method() {
        DateTime dateTime = factory.getDateTime();
        //use dateTime to perform some operations
    }
}

Dans votre test, vous pouvez faire quelque chose comme: when(factoryMock.getDateTime()).doReturn(dateTimeMock)

La maquette d'usine devrait être injectée dans la classe d'une manière ou d'une autre.

0
Matt