LocalDateTime.of returns 空

LocalDateTime.of returns null

我正在尝试对使用 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 值。为什么?

所以 PowerMockito.mockStatic 弄乱了下一行代码。只需将 fixedPointInTime 的实例化移动到 mockStatic 之前执行....使其全部工作。

根据 documentation:

Use PowerMock.mockStatic(ClassThatContainsStaticMethod.class) to mock all methods of this class.

和:

Note that you can mock static methods in a class even though the class is final. The method can also be final. To mock only specific static methods of a class refer to the partial mocking section in the documentation.

To mock a static method in a system class you need to follow this approach.

您告诉它模拟所有静态方法,但没有为 of() 方法提供模拟。

解决方法:要么为of()方法添加mock,要么改为使用部分mocking,这样of()方法就不会被mock了。

基本上,阅读并遵循文档的说明

correctly explains about PowerMock usage (and you also figured out ).

我只想添加一种不同的方法。为了测试当前的 date/time,您可以使用 java.time.Clock。有了这个class,你就可以创建一个fixed clock (a Clock that always returns the same current date/time) and use it in your test.

有了这个,就不需要模拟静态方法(我不得不从测试中删除 PowerMock 注释 class)。唯一的区别是时钟必须传递给 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) 创建了一个新实例,尽管所有实例都对应于相同的 date/time(这才是最重要的,IMO)。


PS: 在上面的代码中,我使用了 JVM 默认时区 (ZoneId.systemDefault())。唯一的问题是它 ,因此最好始终明确说明您使用的是哪一个。

在此特定代码中,时区部分被忽略,因此您可以使用任何时区,这不会有太大区别 - 除非您在夏令时转换发生时获得时区和本地日期的组合,这会产生意想不到的结果。

如果您不想依赖它,可以替换 ZoneId.systemDefault() 并改用 ZoneOffset.UTC(UTC 没有任何夏令时效果)。在这种情况下,您可以像这样创建时钟:

ZoneOffset utc = ZoneOffset.UTC;
Clock clock = Clock.fixed(fixedPointInTime.toInstant(utc), utc);

在您的 class 中创建一个方法,例如

public class SomeClass{

    public static void main(String[] args) {
        LocalDateTime now = getCurrentLocalDateTime(); 
        System.out.println(now);
    }

    private LocalDateTime getCurrentLocalDateTime() {
        return LocalDateTime.now();
    }

}

并且在 Test Class 你使用:

@PrepareForTest(SomeClass.class)

@RunWith(PowerMockRunner.class)

在测试用例中:

LocalDateTime tommorow= LocalDateTime.now().plusDays(1);

SomeClass classUnderTest = PowerMockito.spy(new SomeClass());

PowerMockito.when(classUnderTest, "getCurrentLocalDateTime").thenReturn(tommorow);