LocalDateTime.of返回null
我想单元测试使用java.time.LocalDateTime
的代码。我能够得到模拟工作,但是当我添加时间(无论是分钟还是天)时,我最终得到的值为null
。LocalDateTime.of返回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)
嘲笑此类的所有方法。
和:
请注意,您可以模拟一个类的静态方法,即使类是final。该方法也可以是最终的。 若要仅模拟特定类的静态方法,请参阅文档中的partial mocking部分。
要嘲笑系统类中的静态方法,您需要遵循this的方法。
你告诉它模拟所有的静态方法,但没有提供of()
方法的模拟。
解决方案:添加模拟为of()
方法,或改变使用局部嘲笑,所以of()
方法没有嘲笑。
基本上,阅读并遵循文档的说明。
所以PowerMockito.mockStatic搞乱了下一行代码。只需移动fixedPointInTime的实例即可在mockStatic ....之前执行,使其一切正常。
@Andreas' answer正确地解释了PowerMock的用法(并且你也计算出了in your own answer)。
我只是想添加一个不同的方法。为了测试当前日期/时间,您可以使用java.time.Clock
。通过此课程,您可以创建fixed clock(始终返回相同的当前日期/时间的Clock
)和use it in your test。因此,不需要模拟静态方法(我不得不从测试类中删除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()
)的代码。唯一的问题是它can be changed without notice, even at runtime,所以最好总是明确你正在使用哪一个。
在这个特定的代码中,时区部分被忽略,因此您可以使用任何区域,这并没有太大的区别 - 除非您在夏令时切换时发生时区和本地日期的组合,这会产生意想不到的结果。
如果您不想依赖于此,则可以替换ZoneId.systemDefault()
并改为使用ZoneOffset.UTC
(UTC不具有任何夏令时效果)。在这种情况下,你可以创建你的时钟是这样的:
ZoneOffset utc = ZoneOffset.UTC;
Clock clock = Clock.fixed(fixedPointInTime.toInstant(utc), utc);
在你的类像
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);
您是否尝试运行代码没有嘲笑? powermockito很有可能造成这个问题。 – Ali
并考虑重新考虑使用PowerMock(ito);-) – GhostCat
当嘲笑一个Java“系统”类(如'java.time.LocalDateTime')时,PowerMock要求非系统类*使用*该类在'@ PrepareForTest'中列出(正如其他答案中已经指出的那样)。但根据我的经验,像这样的测试中最大的错误是甚至会引起嘲笑日期/时间戳或系统时钟的想法。如果SUT使用'LocalDateTime.now()',那么它很可能应该允许从外部(通过调用者代码)给出一个日期对象,这将使得编写测试时没有任何嘲讽的微不足道。去过也做过。 –