【问题标题】:How to test date created with LocalDateTime.now()如何测试使用 LocalDateTime.now() 创建的日期
【发布时间】:2016-09-16 09:15:04
【问题描述】:

我有这门课

class MyObject {
    private LocalDateTime date;

    public LocalDateTime getDate() { return this.date; }

    public void myMethod() {
        this.date = LocalDateTime.now();
    }
}

如何测试日期是否设置正确?我不能模拟 now() 因为它是静态的,如果我在测试中使用 LocalDateTime 两个日期将不一样。

【问题讨论】:

标签: java unit-testing date


【解决方案1】:

我不能模拟 now() 因为它是静态的

确实 - 但幸运的是,您不必这样做。相反,将“日期/时间提供程序”视为依赖项,并照常注入。 java.time 提供了这样的依赖:java.time.Clock。在测试中,您可以通过Clock.fixed(...) 提供固定时钟(无需模拟),在生产中您可以使用Clock.system(...)

然后您将代码更改为:

class MyObject {
    private final Clock clock;
    private LocalDateTime date;

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

    public LocalDateTime getDate() {
        return this.date;
    }

    public void myMethod() {
        this.date = LocalDateTime.now(clock);
    }
}

... 或者您通常处理依赖项。

【讨论】:

  • 这听起来不错,尽管我们需要引入一个实际上并不真正需要的时钟
  • @iberbeu:嗯,这取决于你对“需要”的定义——我会说它是“需要清楚地表达依赖关系”。您可以引入自己的特定于应用程序的单例,如果您真的需要,请始终使用它,但我个人更愿意明确我将依赖当前时间的位置。
  • 我认识乔恩。我本可以接受这两个答案,但我不得不选择......让我们看看其他用户发现什么更好
  • @iberbeu:如果测试发生在夏令时更改或系统时钟更改时,则接受的答案将失败。我更喜欢将我的测试与系统时钟完全隔离 - 并明确对时钟的依赖。
【解决方案2】:

您可以在调用myMethod() 之前生成一个日期时间,并确保该日期早于或等于getDate() 返回的日期,类似这样:

@Test
public void testDate() {
    MyObject object = new MyObject();
    // Get the current date time 
    LocalDateTime time = LocalDateTime.now();
    // Affect the current date time to the field date
    object.myMethod();
    // Make sure that it is before or equals
    Assert.assertTrue(time.isBefore(object.getDate()) || time.isEqual(object.getDate()));
}

如果您不在乎为您的班级添加耦合,更好的方法可能是为您的班级提供Supplier<LocalDateTime>,如下所示:

public class MyObject {
    private final Supplier<LocalDateTime> supplier;
    private LocalDateTime date;

    public MyObject() {
        this(LocalDateTime::now);
    }

    public MyObject(final Supplier<LocalDateTime> supplier) {
        this.supplier = supplier;
    }

    public LocalDateTime getDate() { return this.date; }

    public void myMethod() {
        this.date = supplier.get();
    }
}

这样可以很容易地在您的测试用例中创建一个Supplier 用于测试目的。

例如,测试用例可以是:

@Test
public void testDate() {
    LocalDateTime time = LocalDateTime.now();
    MyObject object = new MyObject(() -> time);
    object.myMethod();
    Assert.assertTrue(time.isEqual(object.getDate()));
}

【讨论】:

  • 这种方法易于理解和实施,而且很有效。无论如何,我认为这还不够准确......在某些情况下,这将是要走的路,但通常我更喜欢乔恩的回答
  • 我知道这确实是一个好方法,即使我个人不喜欢仅仅为了一个简单的测试用例就为你的类添加耦合
  • 我同意这一点!引入时钟是有争议的。正如我所说,我会经常使用你的方法,但作为答案,我认为 Jon 的方法更通用、更精确......
  • 检查我的回复更新,我更愿意使用供应商,因为它更通用
【解决方案3】:

如下更新您的课程:

class MyObject {
    private LocalDateTime date;

    public Supplier<LocalDateTime> localDateTime = ()-> LocalDateTime.now();

    public LocalDateTime getDate() { return this.date; }

    public void myMethod() {
        this.date = localDateTime.get();
    }
}

在测试方法中,在调用 myMethod 之前更新供应商变量如下:

objMyObject.localDateTime = ()-> LocalDateTime.parse("2020-11-24T23:59:59.999");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 2017-04-10
    相关资源
    最近更新 更多