How to mock new Date() in java using Mockito

匿名 (未验证) 提交于 2019-12-03 02:18:01

问题:

I have a function that uses the current time to make some calculations. I'd like to mock it using mockito.

An example of the class I'd like to test:

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

I'd like something like:

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

Is it possible to mock that? I wouldn't like to change the "tested" code in order to be tested.

回答1:

The right thing to do is to restructure your code to make it more testable as shown below. Restructuring your code to remove the direct dependency on Date will allow you to inject different implementations for normal runtime and test runtime:

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);     } } 


回答2:

If you have legacy code that you cannot refactor and you do not want to affect System.currentTimeMillis(), try this using Powermock and 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   } } 


回答3:

You could do this by using PowerMock, which augments Mockito to be able to mock static methods. You could then mock System.currentTimeMillis(), which is where new Date() ultimately gets the time from.

You could. I'm not going to advance an opinion on whether you should.



回答4:

One approach, that does not directly answer the question but might solve the underlying problem (having reproducible tests), is allow the Date as an parameter for tests and add a delegate to the default date.

Like so

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

In production code, you use getDoubleTime() and test against getDoubleTime(Date date).



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!