我正在尝试将使用java.time.LocalDateTime
的测试代码单位。我能够使模拟工作,但是当我添加时间(分钟或几天)时,我最终会获得null
值。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ LocalDateTime.class })
public class LocalDateTimeMockTest
{
@Test
public void shouldCorrectlyCalculateTimeout()
{
// arrange
PowerMockito.mockStatic(LocalDateTime.class);
LocalDateTime fixedPointInTime = LocalDateTime.of(2017, 9, 11, 21, 28, 47);
BDDMockito.given(LocalDateTime.now()).willReturn(fixedPointInTime);
// act
LocalDateTime fixedTomorrow = LocalDateTime.now().plusDays(1); //shouldn't this have a NPE?
// assert
Assert.assertTrue(LocalDateTime.now() == fixedPointInTime); //Edit - both are Null
Assert.assertNotNull(fixedTomorrow); //Test fails here
Assert.assertEquals(12, fixedTomorrow.getDayOfMonth());
}
}
我理解(我想我愿意)LocalDateTime
是不变的,我认为我应该得到一个新实例而不是null
值。
事实证明,是.of
方法给我一个null
值。为什么?
根据文档:
使用
PowerMock.mockStatic(ClassThatContainsStaticMethod.class)
进行模拟所有此类的方法。
和:
请注意,即使该类是最终的,您也可以在类中模拟静态方法。该方法也可以是最终的。仅模拟类的特定静态方法,请参阅文档中的部分模拟部分。
要在系统类中模拟静态方法,您需要遵循此方法。
您告诉它要模拟所有静态方法,但没有为of()
方法提供模拟。
解决方案:为of()
方法添加模拟,或更改以使用部分模拟,因此未模拟of()
方法。
基本上,读取并按照文档的说明。
@andreas'正确解释了有关PowerMock用法的解释(您还在自己的答案中弄清楚)。
我只想添加另一种方法。为了测试当前日期/时间,您可以使用java.time.Clock
。使用此类,您可以创建一个固定时钟(Clock
总是返回相同的当前日期/时间)并在测试中使用它。
这样,就无需模拟静态方法(我必须删除测试类中的PowerMock注释)。唯一的区别是时钟必须传递到now()
方法:
@Test
public void shouldCorrectlyCalculateTimeout() {
// create a clock that always returns the same current date/time
LocalDateTime fixedPointInTime = LocalDateTime.of(2017, 9, 11, 21, 28, 47);
ZoneId zone = ZoneId.systemDefault();
Clock clock = Clock.fixed(fixedPointInTime.atZone(zone).toInstant(), zone);
// use the clock in now() method
LocalDateTime fixedTomorrow = LocalDateTime.now(clock).plusDays(1);
// assert (use equals() instead of == because it doesn't return the same instance)
Assert.assertTrue(LocalDateTime.now(clock).equals(fixedPointInTime));
Assert.assertNotNull(fixedTomorrow);
Assert.assertEquals(12, fixedTomorrow.getDayOfMonth());
}
我必须使用equals()
方法(而不是==
)来比较日期,因为now(clock)
创建了一个新实例,尽管所有实例都将与同一日期/时间相对应(这就是重要的,IMO)。
ps:在上面的代码中,我正在使用JVM默认时区(ZoneId.systemDefault()
)。唯一的问题是,即使在运行时,也可以在不通知的情况下进行更改,因此最好始终将其明确显示。
在此特定代码中,时区部分被忽略,因此您可以使用任何区域,这不会有太大的不同 - 除非您在发生日光节省时间转换时得到了时区和本地日期的组合,否则会产生意外的结果。
如果您不想依靠它,则可以替换ZoneId.systemDefault()
并改用ZoneOffset.UTC
(UTC没有任何日光节省效果)。在这种情况下,您可以这样创建时钟:
ZoneOffset utc = ZoneOffset.UTC;
Clock clock = Clock.fixed(fixedPointInTime.toInstant(utc), utc);
,因此powermockito.mockstatic与下一行代码混乱。只需将固定点的实例化以在模型之类之前执行。...
在类中创建一个方法
public class SomeClass{
public static void main(String[] args) {
LocalDateTime now = getCurrentLocalDateTime();
System.out.println(now);
}
private LocalDateTime getCurrentLocalDateTime() {
return LocalDateTime.now();
}
}
,在Test
类中,您使用:
@PrepareForTest(SomeClass.class)
@RunWith(PowerMockRunner.class)
在测试柜中:
LocalDateTime tommorow= LocalDateTime.now().plusDays(1);
SomeClass classUnderTest = PowerMockito.spy(new SomeClass());
PowerMockito.when(classUnderTest, "getCurrentLocalDateTime").thenReturn(tommorow);