How can I mock java.time.LocalDate.now()
在我的测试案例中,我需要测试时间敏感的方法,在该方法中,我们使用的是Java 8类LocalDate,它不是Joda。
运行测试时,我该怎么做才能更改时间
在代码中,将
然后,您可以通过
这是一个例子:
首先,注入
1 2 3 4 | @Bean public Clock clock() { return Clock.systemDefaultZone(); } |
其次,在您的代码中调用
1 2 3 4 5 6 7 8 9 10 | @Component public class SomeClass{ @Autowired private Clock clock; public LocalDate someMethod(){ return LocalDate.now(clock); } } |
现在,在单元测试类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // Some fixed date to make your tests private final static LocalDate LOCAL_DATE = LocalDate.of(1989, 01, 13); // mock your tested class @InjectMocks private SomeClass someClass; //Mock your clock bean @Mock private Clock clock; //field that will contain the fixed clock private Clock fixedClock; @Before public void initMocks() { MockitoAnnotations.initMocks(this); //tell your tests to return the specified LOCAL_DATE when calling LocalDate.now(clock) fixedClock = Clock.fixed(LOCAL_DATE.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); doReturn(fixedClock.instant()).when(clock).instant(); doReturn(fixedClock.getZone()).when(clock).getZone(); } @Test public void testSomeMethod(){ // call the method to test LocalDate returnedLocalDate = someClass.someMethod(); //assert assertEquals(LOCAL_DATE, returnedLocalDate); } |
您可以重构代码以使其易于测试,例如,将
另外,您可以使用PowerMock的模拟静态。
如果我们需要模拟像now()这样的静态方法,我们可以使用PowerMock等多种替代方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @RunWith(PowerMockRunner.class) @PrepareForTest({ LocalDateTime.class }) public class LocalDateTimeUnitTest { @Test public void givenLocalDateTimeMock_whenNow_thenGetFixedLocalDateTime() { Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC")); LocalDateTime dateTime = LocalDateTime.now(clock); mockStatic(LocalDateTime.class); when(LocalDateTime.now()).thenReturn(dateTime); String dateTimeExpected ="2014-12-22T10:15:30"; LocalDateTime now = LocalDateTime.now(); assertThat(now).isEqualTo(dateTimeExpected); } } |
或JMockit,实际上,通过JMockit,我们可以使用MockUp类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Test public void givenLocalDateTimeWithJMock_whenNow_thenGetFixedLocalDateTime() { Clock clock = Clock.fixed(Instant.parse("2014-12-21T10:15:30.00Z"), ZoneId.of("UTC")); new MockUp<LocalDateTime>() { @Mock public LocalDateTime now() { return LocalDateTime.now(clock); } }; String dateTimeExpected ="2014-12-21T10:15:30"; LocalDateTime now = LocalDateTime.now(); assertThat(now).isEqualTo(dateTimeExpected); } |
或Expectations类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Test public void givenLocalDateTimeWithExpectations_whenNow_thenGetFixedLocalDateTime() { Clock clock = Clock.fixed(Instant.parse("2014-12-23T10:15:30.00Z"), ZoneId.of("UTC")); LocalDateTime dateTimeExpected = LocalDateTime.now(clock); new Expectations(LocalDateTime.class) { { LocalDateTime.now(); result = dateTimeExpected; } }; LocalDateTime now = LocalDateTime.now(); assertThat(now).isEqualTo(dateTimeExpected); } |
我们可以在这里找到更多示例。
另一个简单的选择是将now()方法与固定的Clock实例一起使用。当然,java.time包中的大多数类都具有带有Clock参数的now()方法:
1 2 3 4 5 6 7 8 9 | @Test public void givenFixedClock_whenNow_thenGetFixedLocalDateTime() { Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC")); String dateTimeExpected ="2014-12-22T10:15:30"; LocalDateTime dateTime = LocalDateTime.now(clock); assertThat(dateTime).isEqualTo(dateTimeExpected); } |
您可能还希望在生产中传递一个固定的时钟(该值在事务开始时是固定的),以避免在不同的实体和请求中使用不一致的"现在"。
有关详细信息,请参见此问题。
使用Spring:
ClockConfiguration类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Configuration public class ClockConfiguration { private final static LocalDate LOCAL_DATE = LocalDate.of(2019, 12, 17); @Bean @ConditionalOnMissingBean Clock getSystemDefaultZoneClock() { return Clock.systemDefaultZone(); } @Bean @Profile("test") @Primary Clock getFixedClock() { return Clock.fixed(LOCAL_DATE.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); } } |
SomeService类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Service @RequiredArgsConstructor public class SomeService { private final Clock clock; public void someMethod(){ ... LocalDateTime.now(clock) LocalDate.now(clock) ... } } |
您必须在测试中具有有效的"测试"配置文件:
SomeServiceTest类:
1 2 3 4 5 6 | @ActiveProfiles("test") @EnableConfigurationProperties @SpringBootTest(classes = [YourAppMainClass]) class SomeServiceTest { ... } |