使用PowerMockRunner和LocalDate类模拟今天的日期

时间:2018-10-02 15:21:18

标签: java junit mockito powermock localdate

请考虑如下使用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初始化移到时为什么失败了?

进一步,这个测试可以改进吗?

3 个答案:

答案 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,并在测试过程中将其替换为模拟!