时间依赖的unit testing

我需要testing一个函数,其结果取决于当前时间(使用Joda时间的isBeforeNow() )。

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

是否有可能使用Mockito来存储/模拟系统时间,以便可靠地testing该函数?

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

http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeUtils.html

让你的代码可testing的最好方法(IMO)是将“当前时间是什么”的依赖关系提取到它自己的接口中,使用当前系统时间的实现(正常使用)和允许你设置时间的实现,按照你的意愿推进

我已经在各种情况下使用这种方法,并且运作良好。 这很容易设置 – 只需创build一个接口(例如Clock ),它有一个单一的方法,以任何你想要的格式(例如使用乔达时间,或可能是一个Date )给你当前的瞬间。

Java 8引入了抽象类java.time.Clock ,它允许您有一个替代的testing实现。 这正是Jon在他回答的时候所build议的。

要添加到Jon Skeet的答案 ,Joda时间已经包含一个当前时间接口: 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)); } } 

在unit testing中嘲弄时间(使用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 )创build一个专门的接口,而是通常创build一个特殊的testing接口(比如MockupFactory )。 我把所有的方法,我需要testing的代码。 例如,在我的一个项目中,我有四个方法:

  • 一个返回一个模拟数据库客户端;
  • 一个创build一个模型通知对象,通知代码关于数据库的变化;
  • 一个创build一个模拟java.util.Timer,当我想要的时候运行任务;
  • 一个返回当前时间。

被testing的类有一个接受这个接口和其他参数的构造函数。 没有这个参数的人只是创build一个“现实生活中”的接口的默认实例。 接口和构造函数都是包私有的,所以testingAPI不会泄漏到包之外。

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

这样我就可以devise出适合于testing的代码,而不会对代码本身造成太大的影响。 事实上,由于许多工厂代码被集中在一个地方,代码变得更清洁。 例如,如果我需要切换到另一个实际代码的数据库客户端实现,我只需要修改一行而不是四处search对构造函数的引用。

当然,就像Jon的做法一样,它不适用于你无法修改或者不允许修改的第三方代码。