繁体   English   中英

时间相关单元测试

[英]Time dependent unit tests

我需要测试一个函数,其结果将取决于当前时间(使用 Joda 时间的isBeforeNow() ,它发生了)。

public boolean isAvailable() {
    return (this.someDate.isBeforeNow());
}

是否可以使用(例如,使用 Mockito)存根/模拟系统时间,以便我可以可靠地测试该功能?

使您的代码可测试的最佳方法 (IMO) 是将“当前时间是什么”的依赖关系提取到其自己的接口中,并使用使用当前系统时间(正常使用)的实现和允许您设置时间的实现,根据需要推进它等。

我在各种情况下都使用过这种方法,而且效果很好。 它很容易设置 - 只需创建一个界面(例如Clock ),该界面具有单一方法,可以以您想要的任何格式(例如使用 Joda Time 或可能的Date )为您提供当前时刻。

Joda 时间支持通过DateTimeUtils类的setCurrentMillisFixedsetCurrentMillisOffset方法设置“假”当前时间。

https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html

Java 8 引入了抽象类java.time.Clock ,它允许您有一个替代的测试实现。 这正是乔恩当时在他的回答中所建议的。

要添加到Jon Skeet 的答案中,Joda Time 已经包含一个当前时间接口: DateTimeUtils.MillisProvider

例如:

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils.MillisProvider;

public class Check {
    private final MillisProvider millisProvider;
    private final DateTime someDate;

    public Check(MillisProvider millisProvider, DateTime someDate) {
        this.millisProvider = millisProvider;
        this.someDate = someDate;
    }

    public boolean isAvailable() {
        long now = millisProvider.getMillis();
        return (someDate.isBefore(now));
    }
}

在单元测试中模拟时间(使用Mockito,但您可以实现自己的类 MillisProviderMock):

DateTime fakeNow = new DateTime(2016, DateTimeConstants.MARCH, 28, 9, 10);
MillisProvider mockMillisProvider = mock(MillisProvider.class);
when(mockMillisProvider.getMillis()).thenReturn(fakeNow.getMillis());

Check check = new Check(mockMillisProvider, someDate);

在生产中使用当前时间( DateTimeUtils.SYSTEM_MILLIS_PROVIDER在 2.9.3 中被添加到 Joda 时间):

Check check = new Check(DateTimeUtils.SYSTEM_MILLIS_PROVIDER, someDate);

我使用了一种类似于 Jon 的方法,但不是只为当前时间创建一个专门的接口(比如Clock ),我通常创建一个特殊的测试接口(比如MockupFactory )。 我把测试代码所需的所有方法都放在那里。 例如,在我的一个项目中,我有四种方法:

  • 一个返回一个模型数据库客户端;
  • 创建一个模型通知程序对象,通知代码有关数据库中的更改;
  • 创建一个模型 java.util.Timer 在我想要的时候运行任务;
  • 一个返回当前时间。

被测试的类有一个构造函数,它在其他参数中接受这个接口。 没有这个参数的只是创建了这个界面的一个默认实例,它可以“在现实生活中”工作。 接口和构造函数都是包私有的,因此测试 API 不会泄漏到包之外。

如果我需要更多模仿对象,我只需向该接口添加一个方法并在测试和实际实现中实现它。

通过这种方式,我首先设计了适合测试的代码,而不会对代码本身施加太多影响。 事实上,由于大量的工厂代码集中在一个地方,因此代码变得更加清晰。 例如,如果我需要在实际代码中切换到另一个数据库客户端实现,我只需要修改一行,而不是四处寻找对构造函数的引用。

当然,就像 Jon 的方法一样,它不适用于您无法或不允许修改的 3rd 方代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM