所以我有一个类有一个方法“getDaysUntil(Date date)”,它返回作为参数给出的日期之前的天数。我提到我不能改变下面的课程:
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(),但无济于事。
有没有办法正确测试这些方法?
答案 0 :(得分: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);
}
答案 1 :(得分:0)
使用用作DateFactory的类,该类将被调用以在您的应用程序代码中构造Date对象。
然后仅在单元测试中模拟该DateFactory的方法。这样,您就可以使其返回任意日期作为虚拟“当前日期”
答案 2 :(得分:-1)
我知道您无法更改需要测试的方法。不幸的是,这也意味着你会遇到旧的,通常不是程序员友好的Date
类(我假设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
。