使用Java 8 Date / Time类编写和测试便捷方法

时间:2018-10-23 19:16:20

标签: java java-time

我有一些用Calendars编写的旧方便方法,我想对其进行更新以使用Java 8中引入的Java.time。*类。我类中的某些方法获得的数量如当前时间,甚至只是当前时间。

我计划为每种方法编写两种变体:一种假定时区是此计算机上定义的默认时区,另一种允许用户指定所需的时区。

我正在尝试弄清两个主要问题:

  1. 如何在我的方法中获取当前时间戳。
  2. 如何使用当前时间戳记的不同源对结果进行单元测试。

关于方法本身,我倾向于如下创建一个ZonedDateTime:

LocalDateTime currentDateTime = LocalDateTime.now();
ZoneId timeZoneDefault = ZoneId.systemDefault(); 
ZonedDateTime currentZonedDateTimeDefault = ZonedDateTime.of(currentDateTime, timeZoneDefault);

然后,我将使用DateTimeFormatter获得我真正关心的结果部分。例如,如果我要从24小时制开始,然后从12小时制开始,请执行以下操作:

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("kk");
System.out.println("currentHour (24 hour clock): " + currentZonedDateTimeDefault.format(fmt));
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("hh a");
System.out.println("currentHour (12 hour clock): " + currentZonedDateTimeDefault.format(fmt2));

到目前为止可以吗?还是应该使用其他方法,也许使用Instant?

我的主要问题是想出另一种方法来获取单元测试的当前时间,以便可以将预期结果与实际结果进行比较。我一直在阅读有关Clocks和Instants的信息,等等。阅读的内容越多,我就越会感到困惑。有些方法似乎是从同一来源获取当前时间,因此它们可能会显示预期结果始终与实际结果相同-但是两者都可能以相同的方式出错。

有人能指导我以最佳方式计算给定时区中的当前时间吗?该时间域与我在方法中使用的方式相比,会以不同的方式获得时间?

更新: 我正在研究便捷方法,并且在获取当前日期和时间开始的每种方法中都使用此方法:

    LocalDateTime now = LocalDateTime.now();
    ZonedDateTime nowLocalTimeZone = ZonedDateTime.of(now, ZoneId.systemDefault());

然后,使用以下代码获取我真正想要的日期/时间部分:

try {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(MONTH_NUMBER_FORMAT);
        return Integer.parseInt(nowLocalTimeZone.format(format));
    }
    catch (DateTimeParseException excp) {
        throw excp;         
    }

请注意,在这些方法中,所有内容均基于LocalDateTime.now()且未指定任何时钟。

在单元测试中,我将其作为类变量:

    private Clock localClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());

在典型的单元测试中,我有这样的代码:

@Test
@DisplayName ("getCurrentMonthNumberLocal()")
void testGetCurrentMonthNumberLocal() {

    LocalDateTime now = LocalDateTime.now(localClock);
    ZonedDateTime nowLocalTimeZone = ZonedDateTime.of(now, ZoneId.systemDefault());

    //Normal cases
    assertEquals(nowLocalTimeZone.getMonthValue(), CurrentDateTimeUtils.getCurrentMonthNumberLocal());
}

请注意,此方法涉及使用名为localClock的固定Clock作为预期结果的来源。

我运行测试时,预期结果与实际结果相符(至少对于到目前为止我运行过的少数几门课,它们查找年和月的数字)。

这种方法是否可以确保我从两个不同的来源获取当前时间,以便进行比较?还是我可以从完全相同的来源(例如计算机上的系统时钟)有效地获取相同的信息?

我非常希望从方法中获得的日期/时间与用于确定单元测试中预期结果的日期/时间来自不同的来源,以便确保它是有效的测试,否则,我对测试这些方法没有多大意义。 (我想我可以只显示每个函数的结果,看看它是否近似正确。很容易就能确定年,月和日是否正确,除非您可能非常接近该年末,月或日。一天,在这种情况下,您实际上可能会看到其他时区的值,却不知道。)

1 个答案:

答案 0 :(得分:1)

在测试中(并且仅在测试期间!),设置便利类使用的时钟,以便您可以独立于计算机时钟来预测期望/预期的结果:

{
0: {year: 2018}
1: {year: 2019}
2: {year: 2020}
3: {year: 2021}
4: {year: 2022}
5: {year: 2023}
6: {year: 2024}
7: {year: 2025}
8: {year: 2026}
9: {year: 2027} 
}

要使其正常工作,当然需要您的便利班级可以接受public class ConvenienceTest { @Test public void testGetLocalHour() { Convenience underTest = new Convenience(); ZoneId zone = ZoneId.of("America/Los_Angeles"); ZonedDateTime fixedZdt = ZonedDateTime.now(zone).withHour(0); underTest.setClock(Clock.fixed(fixedZdt.toInstant(), zone)); assertEquals("24", underTest.getLocalHour24HourClock()); fixedZdt = fixedZdt.withHour(1); underTest.setClock(Clock.fixed(fixedZdt.toInstant(), zone)); assertEquals("01", underTest.getLocalHour24HourClock()); fixedZdt = fixedZdt.withHour(23); underTest.setClock(Clock.fixed(fixedZdt.toInstant(), zone)); assertEquals("23", underTest.getLocalHour24HourClock()); // TODO test with other time zones } } 并使用它:

Clock

通过此实现,测试刚刚在我的计算机上通过。

后退一步:如果您的便利方法只是java.time之上的一薄层,您可能会开始考虑单元测试的价值。如果它在做一些实际的工作(例如上例中的格式化,经常会出错),则测试很有价值,但是如果某个方法仅从对java.time的单次调用中返回一个值,则可能不需要测试。您不应该测试java.time,最好只测试自己的代码。