首页 > 解决方案 > Java,TDD 不等于时为真?

问题描述

出于某种原因,在课堂上测试此方法时,我们发现了一个我们无法理解的问题。System.out.println();当出于某种原因写作时它通过了?有人可以解释为什么会这样吗?

public class Zones {

public ZoneId getZoneId(String input) {

    if (input.equalsIgnoreCase("Stockholm")) {
        return ZoneId.of("Europe/Stockholm");
    }
    else if (input.equalsIgnoreCase("Shanghai")) {
        return ZoneId.of("Asia/Shanghai");
    } else if (input.equalsIgnoreCase("Toronto")) {
        return ZoneId.of("America/Toronto");
    }
    else if (input.equalsIgnoreCase("Hamburg")) {
        return ZoneId.of("Europe/Berlin");
    }
    else return null;
}

public LocalDateTime getZoneTime(ZoneId zoneId) {
    LocalDateTime lt = LocalDateTime.now(zoneId);
    return lt;
}

}

private Zones z = new Zones();

@Test
public void getZoneTimeTest () {
    System.out.println(z.getZoneTime(zIDToronto).getNano() );
    System.out.println(LocalDateTime.now(zIDToronto).getNano() );
    assertTrue(z.getZoneTime(zIDToronto).getNano() == LocalDateTime.now(zIDToronto).getNano());
}

标签: javatdd

解决方案


终于有时间更深入地调查了。

我开始试验,过了一会儿发现,实际上System.out.println影响结果的不是它的存在,而是你LocalDateTime在它之前实例化了 2 个实例。

深入挖掘LocalDateTimeSystemClock(它所委托的)代码,我发现亚毫微精度是通过调用本机调用实现的jdk.internal.misc.VM#getNanoTimeAdjustment

最后一次调用是特定于操作系统的。我对它进行了一些试验,发现它不会线性返回值,因为它在循环中被调用(假设我的循环运行得相当规律)。

所以我决定运行一些代码来映射返回的 nano 值。

我做了这个采样代码:

Clock clock = Clock.systemDefaultZone();

int samples = 1_000;
LocalDateTime[] instants = new LocalDateTime[samples];

int k = 0;

for (int i = 0; i < samples; i++) {
    instants[i] = LocalDateTime.now(clock);
    for (int j = 0; j < 10000; j++) {
        k = j % 2;
    }
}

将值写入文件,然后将纳米差异与第一个值映射到图表中:

纳米级数与第一次调用

As you can see this graph (of 1000 values) makes intermittent leaps. This is obviously in part due to precision restriction of the underlying system. But wat struck me is that the first two values consistently were different. It's as if upon regular access the OS system starts caching the value for a while (possibly to avoid strain on the system resources).

But the result it seems is that you set yourself up for getting the same value on the 3rd and 4th call (unless enough time has passed).

That would explain why your test passes with, and fails without those prior instantiations.

顺便说一句,对于单元测试,您不想依赖系统时钟。确保您的业务代码从注入的 Clock 实例中获取时间。然后,您可以为测试注入自定义时钟,并测试您的代码是在 DST 转换日期还是在闰日运行,而无需等待几个月。


推荐阅读