Comment se moquer de new Date () en java en utilisant Mockito

j'ai une fonction qui utilise le temps de faire quelques calculs. J'aimerais me moquer avec mockito.

Un exemple de la classe que j'aimerais tester:

public class ClassToTest {
    public long getDoubleTime(){
        return new Date().getTime()*2;
    }
}

j'aimerais quelque chose comme:

@Test
public void testDoubleTime(){
   mockDateSomeHow(Date.class).when(getTime()).return(30);
   assertEquals(60,new ClassToTest().getDoubleTime());
}

Est-il possible de se moquer de qui? Je ne voudrais pas changer le "testé" code pour être testé.

31
demandé sur Marian Paździoch 2012-08-09 20:24:44

5 réponses

la bonne chose à faire est de restructurer votre code pour le rendre plus testable comme indiqué ci-dessous. Restructurer votre code pour supprimer la dépendance directe à la Date vous permettra d'injecter différentes implémentations pour l'exécution normale et tester l'exécution:

interface DateTime {
    Date getDate();
}

class DateTimeImpl implements DateTime {
    @Override
    public Date getDate() {
       return new Date();
    }
}

class MyClass {

    private final DateTime dateTime;
    // inject your Mock DateTime when testing other wise inject DateTimeImpl

    public MyClass(final DateTime dateTime) {
        this.dateTime = dateTime;
    }

    public long getDoubleTime(){
        return dateTime.getDate().getTime()*2;
    }
}

public class MyClassTest {
    private MyClass myClassTest;

    @Before
    public void setUp() {
        final Date date = Mockito.mock(Date.class);
        Mockito.when(date.getTime()).thenReturn(30L);

        final DateTime dt = Mockito.mock(DateTime.class);
        Mockito.when(dt.getDate()).thenReturn(date);

        myClassTest = new MyClass(dt);
    }

    @Test
    public void someTest() {
        final long doubleTime = myClassTest.getDoubleTime();
        assertEquals(60, doubleTime);
    }
}
44
répondu munyengm 2012-08-09 21:38:01

si vous avez un code d'héritage que vous ne pouvez pas modifier et que vous ne voulez pas affecter System.currentTimeMillis(), essayez ceci à l'aide de Powermock et PowerMockito

//note the static import
import static org.powermock.api.mockito.PowerMockito.whenNew;

@PrepareForTest({ LegacyClassA.class, LegacyClassB.class })

@Before
public void setUp() throws Exception {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("PST"));

    Date NOW = sdf.parse("2015-05-23 00:00:00");

    // everytime we call new Date() inside a method of any class
    // declared in @PrepareForTest we will get the NOW instance 
    whenNew(Date.class).withNoArguments().thenReturn(NOW);

}

public class LegacyClassA {
  public Date getSomeDate() {
     return new Date(); //returns NOW
  }
}
16
répondu Daniel Mora 2017-12-06 08:14:44

Vous faites ceci en utilisant PowerMock, ce qui augmente Mockito pour pouvoir se moquer des méthodes statiques. Vous pourriez alors faux System.currentTimeMillis(), où new Date() obtient finalement le temps de.

Vous . Je ne vais pas avancer une opinion sur si vous devrait.

6
répondu Tom Anderson 2012-08-09 20:13:29

une approche, qui ne répond pas directement à la question mais pourrait résoudre le problème sous-jacent (ayant des tests reproductibles), est d'autoriser le Date comme paramètre pour les tests et Ajouter un délégué à la date par défaut.

Comme

public class ClassToTest {

    public long getDoubleTime() {
      return getDoubleTime(new Date());
    }

    long getDoubleTime(Date date) {  // package visibility for tests
      return date.getTime() * 2;
    }
}

dans le code de production, vous utilisez getDoubleTime() et tester getDoubleTime(Date date).

1
répondu DerMike 2016-07-05 16:49:02
Date now = new Date();    
now.set(2018, Calendar.FEBRUARY, 15, 1, 0); // set date to 2018-02-15
//set current time to 2018-02-15
mockCurrentTime(now.getTimeInMillis());

private void mockCurrentTime(long currTimeUTC) throws Exception {
    // mock new dates with current time
    PowerMockito.mockStatic(Date.class);
    PowerMockito.whenNew(Date.class).withNoArguments().thenAnswer(new Answer<Date>() {

        @Override
        public Date answer(InvocationOnMock invocation) throws Throwable {
            return new Date(currTimeUTC);
        }
    });

    //do not mock creation of specific dates
    PowerMockito.whenNew(Date.class).withArguments(anyLong()).thenAnswer(new Answer<Date>() {

        @Override
        public Date answer(InvocationOnMock invocation) throws Throwable {
            return new Date((long) invocation.getArguments()[0]);
        }
    });

    // mock new calendars created with time zone
    PowerMockito.mockStatic(Calendar.class);
    Mockito.when(Calendar.getInstance(any(TimeZone.class))).thenAnswer(new Answer<Calendar>() {
        @Override
        public Calendar answer(InvocationOnMock invocation) throws Throwable {
            TimeZone tz = invocation.getArgumentAt(0, TimeZone.class);
            Calendar cal = Calendar.getInstance(tz);
            cal.setTimeInMillis(currTimeUTC);
            return cal;
        }
    });
}
0
répondu Avraham Shalev 2018-04-10 12:01:14