【问题标题】:How do I simulate the passage of time with java.time.Clock?如何使用 java.time.Clock 模拟时间的流逝?
【发布时间】:2022-01-03 14:52:22
【问题描述】:

假设我有这个类,ClassToBeTested,它的方法调用之间的时间间隔很重要。 foo 返回不同的值,具体取决于您在过去 x 小时内是否调用了 foo

我实现这一点的方式是在调用foo 时获取当前的Instant,并将其与调用foo 的最后一个Instant 进行比较,我将其存储在一个字段中。

由于ClassToBeTested取决于当前时间,所以我添加了一个Clock字段,调用者在创建ClassToBeTested时需要传入:

class ClassToBeTested {
    private final Clock clock;
    private Instant lastCalled;

    public ClassToBeTested(Clock clock) {
        this.clock = clock;
    }

    public String foo() {
        if (lastCalled == null || Duration.between(lastCalled, Instant.now(clock)).compareTo(Duration.ofHours(1)) >= 0) {
            lastCalled = Instant.now(clock);
            return "A";
        } else {
            lastCalled = Instant.now(clock);
            return "B";
        }
    }
}

不过,当我编写测试时,我意识到没有工厂方法可以创建可变的Clock。我尝试创建自己的可变时钟,以便我的测试看起来像这样:

private final FakeClock fakeClock = new FakeClock();

@Test
public void fooReturnsAAfterAnHour() {
    var myInstance = new ClassToTest(fakeClock);
    assertThat(myInstance.foo(), is("A"));
    fakeClock.goForward1Hour(); // this mutates the clock, and changes what instant() will return
    assertThat(myInstance.foo(), is("A"))
}

@Test
public void fooReturnsBWithinAnHour() {
    var myInstance = new ClassToTest(fakeClock);
    assertThat(myInstance.foo(), is("A"));
    fakeClock.goForward30Minutes(); // this mutates the clock, and changes what instant() will return
    assertThat(myInstance.foo(), is("B"))
}

只是在文档中发现,它说:

所有可以实例化的实现都必须是最终的、不可变的和线程安全的。

因此,Clock 的可变实现似乎是不正确的。但是查看堆栈溢出的帖子,许多人建议使用可变时钟 (example)。 Some 还建议模拟 Clock 抽象类。当我尝试这样做时,jMock(这是我正在使用的)不喜欢它,因为Clock 不是一个接口。显然,if I want to mock classes, I'd have to include another dependency,主要用于模拟遗留代码。对我来说,这听起来不适合嘲笑 Clock

我还可以为ClassToBeTested中的clock字段添加一个setter,这样我就可以做到:

myInstance.setClock(Clock.offset(clock, Duration.ofHours(1)));

让时间提前。但我认为这会破坏封装。

在这一点上,我没有想法。我能做什么?

【问题讨论】:

    标签: java mocking java-time jmock


    【解决方案1】:

    您的FakeClock 方法很好。这就是我会使用的方法。

    如果您更喜欢使用库中的实现而不是您自己的实现,则可以使用 threeten-extra 库中的 MutableClock。该类正是为这个用例而设计的。

    “不可变”要求是 Java 17 中 Clock 类中的 removed。它被删除不是因为对 Clock 的实现进行了更改,而是因为该要求具有有害的限制性(请参阅您的使用案例),而没有服务于有用的目的。因此,如果您使用的是 Java

    【讨论】:

    • 很高兴知道不可变要求已被删除!我想我应该检查更多最新的文档。但是线程安全的要求并没有被删除,这意味着我仍然应该创建变异方法synchronized
    猜你喜欢
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多