2017-03-03 155 views
1

所以我有一个类有一个方法“getDaysUntil(日期日期)”,它返回给定日期的天数作为参数。我提到,我无法改变以下类:当前日期使用新Date()的Java单元测试方法

public class A { 

public int getDaysUntil(Date givenDate) { 

    ... // code 

    Date currentDate = new Date() //it creates a date object holding the current day 

    ...// code that calculates the nr of days between currentDate and givenDate. 

} 

我必须做一些单元测试,你可能会看到这个问题,它里面的方法创建的currentdate和返回值将是每天都不同。我试图用PowerMock模拟Date对象或“覆盖”System.currentTimeMillis(),但无济于事。

有什么办法可以正确地测试这种方法吗?

+3

是的,有很多方法可以做到这一点。一种可能的方式是在[我的答案]中描述(http://stackoverflow.com/q/11042200) –

+1

@DavidWallace基本上所说的。并且请注意,自Java8以来,实际上有一个专门的类可以帮助您,称为java.time.Clock,因此您不必按链接答案中的建议滚动自己的实现。 –

+1

它可能是我,但从@DavidWallace文章,我明白,我要改变原来的方法的代码。我不能那样做。 –

回答

-1

我知道你不能改变你需要测试的方法。不幸的是,这也意味着你坚持使用旧的,往往不是非常程序员友好的类(我假定java.util.Date)。

编辑:您的方法使用的no-arg Date构造函数反过来使用System.currentTimeMillis(),这是一种静态本地方法。我不知道有些工具可以模拟构造函数和静态原生方法,但是被JMockit的开发人员@Rogério评论和answer告知,这种模拟工具存在。

在任何情况下,还存在另一种:你从今天开始计算天数部分,通过所产生的Date的方法,并检查你回来,你在你的计算中使用的数量。这将在任何一天工作,不需要嘲弄/残留。

在下面的代码中,我假定getDaysUntil方法应该放弃小时和分钟,并只看计算机时区中的日期。如果真实需求不同,您可以对我的代码进行适当的调整。

我们想要考虑到该方法可能会在午夜之后运行。如果是这样,我认为结果是未定义的,因为我们不知道Date对象是在午夜之前还是之后构建的。在这种情况下,我只需再试一次,假设测试将在下一个午夜之前完成。

@Test 
public void testGetDaysUntil() { 
    A instanceUnderTest = new A(); 
    for (int daysToTest = 0; daysToTest <= 400; daysToTest++) { 

     LocalDate today; 
     int result; 
     do { 
      today = LocalDate.now(); // do this in each iteration in case day changes underway 
      LocalDate targetDate = today.plusDays(daysToTest); 
      Date midnightAtStartOfDay = Date.from(targetDate.atStartOfDay(ZoneId.systemDefault()) 
                .toInstant()); 
      result = instanceUnderTest.getDaysUntil(midnightAtStartOfDay); 
     } while (! today.equals(LocalDate.now())); // if we have passed midnight, try again 
     assertEquals(daysToTest, result); 

     do { 
      today = LocalDate.now(); 
      LocalDate targetDate = today.plusDays(daysToTest); 
      Date nearMidnightAtEndOfDay = Date.from(targetDate.atTime(23, 59, 59, 400_000_000) 
                 .atZone(ZoneId.systemDefault()) 
                 .toInstant()); 
      result = instanceUnderTest.getDaysUntil(nearMidnightAtEndOfDay); 
     } while (! today.equals(LocalDate.now())); 
     assertEquals(daysToTest, result); 
    } 
} 

我已经使用Java 8类进行日期和时间计算。如果您不能使用Java 8,可以使用Calendar和/或GregorianCalendar,那么这项工作可能会稍微麻烦一点,但至少可以轻松转换为Date

+1

但你*可以*模拟构造函数*还有''本机'方法。检查你的事实。 –

1

一种解决方案,其中System.currentTimeMillis()被嘲笑为如下,使用JMockit库(它应该是可能的PowerMock太):

@Test @SuppressWarnings("deprecation") 
public void daysUntilCurrentDate() { 
    final long fakeCurrentDateInMillis = new Date(2017, 2, 1).getTime(); 
    new MockUp<System>() { 
     @Mock long currentTimeMillis() { return fakeCurrentDateInMillis; } 
    }; 
    A tested = new A(); 

    int daysSinceJan30 = tested.getDaysUntil(new Date(2017, 1, 30)); 

    assertEquals(2, daysSinceJan3O); 
}