使用Java 8 Date/Time类编写和测试便捷方法 [英] Writing and testing convenience methods using Java 8 Date/Time classes

查看:77
本文介绍了使用Java 8 Date/Time类编写和测试便捷方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些用Calendars编写的较旧的便捷方法,我想对其进行更新以使用Java 8中引入的Java.time.*类.当前时间.

I have some old convenience methods, written using Calendars, that I want to update to use the Java.time.* classes introduced in Java 8. Some of the methods in my class get quantities like the current time or even just the current hour.

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

I plan to write two variants of each method: one that assumes that the timezone is the default defined on this computer and one that allows the user to specify the desired timezone.

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

I'm trying to figure out two main things:

  1. 如何在我的方法中获取当前时间戳.
  2. 如何使用当前时间戳记的不同源对我的结果进行单元测试.
  1. How to get the current timestamp in my methods.
  2. How to unit test my results using a different source of the current timestamp.

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

With regards to the methods themselves, I'm inclined to create a ZonedDateTime as follows:

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

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

I would then use a DateTimeFormatter to obtain the part of the result that I actually cared about. For instance, if I wanted the current hour from the 24 hour clock and then from the 12 hour clock, I would do this:

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?

Is that okay so far or should I be using a different approach, perhaps using Instant?

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

My major problem is figuring out a different way to get the current time for my unit tests so that I can compare expected results with actual results. I've been reading about Clocks and Instants and so forth and the more I read, the more I get confused. Some approaches seem to be getting the current time from the same source so they will presumably show that the expected result is ALWAYS the same as the actual result - but then BOTH could be wrong in the same way.

有人可以指导我以最佳方式计算给定时区中的当前时间吗?

Can someone guide me on the best way to compute the current time in a given timezone that gets the time in a different way than the way I am using in my method?

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

UPDATE: I'm working on my convenience methods and am using this in each method that starts out by getting the current date and time:

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

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

Then, I get the part of the date/time that I actually want with code like this:

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

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

Note that within the methods, everything is based on LocalDateTime.now() with NO clock specified.

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

In my unit tests, I've got this as a class variable:

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

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

Within a typical unit test, I have code like this:

@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作为预期结果的来源.

Note that this approach involves using the fixed Clock named localClock as the source of the expected result.

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

When I run the tests, the expected results match the actual result (at least for the few classes I've run so far, which look for year and month number).

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

Does this approach ensure that I'm getting the current time from two DIFFERENT sources so that the comparison is valid? Or am I effectively getting the same information from the exact same source, such as the system clock on my computer?

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

I very much want the date/time I get from the methods to come from a different source than the date/time used to determine the expected results in my unit tests so that I'm sure it's a valid test, otherwise, I don't see much point in testing these methods. (I suppose I could just display the results of each function and see if it seems approximately right. It's pretty easy to tell if the year, month, and day are right unless perhaps you are very close to the end of that year, month or day, in which case you might actually be seeing the values for a different time zone and not know it.)

推荐答案

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

In your test (and only during test!) set the clock that your convenience class uses so that you can predict the desired/expected results independently of the computer clock:

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并使用它:

For this to work it of course requires that your convenience class can accept a Clock and uses it:

public class Convenience {

    private Clock clock = Clock.systemDefaultZone();

    /** For testing only. Sets the clock from which to get the time. */
    void setClock(Clock clockForTest) {
        this.clock  = clockForTest;
    }

    public String getLocalHour24HourClock() {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("kk");
        ZonedDateTime zdt = ZonedDateTime.now(clock);
        return zdt.format(fmt);
    }

}

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

With this implementation the tests just passed on my computer.

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

Stepping a step back: if your convenience methods are but a thin layer on top of java.time, you may start to consider how much value a unit test has. If it is doing some real work (like formatting in the above example, something that regularly goes wrong), a test is valuable, but if a method just returns a value from a single call into java.time, you may not need a test. You shouldn’t test java.time, preferably only your own code.

这篇关于使用Java 8 Date/Time类编写和测试便捷方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆