请考虑如下使用DateUtilTest
的{{1}}类:
PowerMockRunner
我想理解为什么import com.reporting.utils.DateUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.time.LocalDate;
import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@PrepareForTest(DateUtil.class)
@RunWith(PowerMockRunner.class)
public class DateUtilTest {
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
LocalDate expected = LocalDate.of(2017, 10, 13);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
@Test
public void getPreviousWorkingDayAsDate2_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
LocalDate expected = LocalDate.of(2017, 10, 13);
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
}
==> @Test
在将getPreviousWorkingDayAsDate2_whenMonday
模拟之后将expected
LocalDate
初始化移到时为什么失败了?
进一步,这个测试可以改进吗?
答案 0 :(得分:3)
进一步,这个测试可以改进吗?
是-重构DateUtil使其能够使用特定的Clock
。例如:
public class DateUtil {
private static Clock clock = Clock.systemDefaultZone();
public static setClock(Clock clock) {
assertNotProduction(); // optionally check for an environment/system variable to throw exception if used in production
DateUtil.clock = clock;
}
public static Date getPreviousWorkingDayAsDate() {
LocalDate today = LocalDate.now(clock); // use clock
...
return ...;
}
}
然后,单元测试不需要任何模拟。例如:
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate monday = LocalDate.of(2017, 10, 16);
Clock clock = Clock.fixed(monday.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
DateUtil.setClock(clock);
LocalDate lastFriday = LocalDate.of(2017, 10, 13);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(lastFriday), previousWorkingDay);
}
@After
public void resetClock() {
DateUtil.setClock(Clock.systemDefaultZone());
}
答案 1 :(得分:2)
这很简单。当您在模拟LocalDate.class之后将预期的LocalDate初始化移动到时,则该类已经被全局模拟了,就像在每次调用该类时一样。这意味着它没有给您真正的Java实现。这意味着您无法获得LocalDate.of(2017,10,13)的真正Java实现,因为此时您已用模拟版本覆盖了该类。
测试可以改善吗?是的,不要使用powermock。
如果可以避免的话,使用powermock被认为是不好的做法。这是一个漫长的故事,我不确定这是解释这一切的地方。它的简短版本:如果您不使用电源模拟,则必须使代码更加灵活。 Powermock允许您作弊,并且不能使您的代码灵活。使用Power Mock时,在测试和生产代码中不会得到相同的行为。
在此处阅读更多信息: Why not PowerMock
答案 2 :(得分:1)
测试时,日期总是很痛苦的。但是使用DateSupplier
可以很容易地修复它。
DateSupplier
是一个类,您可以在创建“现在”日期的任何地方注入。
将日期创建替换为DateSupplier.get()
。
测试时,您只需模拟DateSupplier并返回所需的日期。
可以在此处找到详细的示例:https://dzone.com/articles/mocking-jodatimes-datetime-and。 (您实际上并不需要番石榴的供应商)
在这种情况下:在您的DateSupplier
类中插入一个DateUtil
,并在测试过程中将其替换为模拟!