使用当前时间条件处理unit testing

我正在为我正在进行的项目中的某些实用程序类设置unit testing,其中一个类(包含许可信息)有一个方法可以根据当前时间进行一些确定。

即许可证包含到期日期,许可证字符串validation该日期,但查看许可证是否过期的实际逻辑基于当前时间。

public boolean isValid() { return isLicenseStringValid() && !isExpired(); } public boolean isExpired() { Date expiry = getExpiryDate(); if( expiry == null ) { return false; } Date now = new Date(); return now.after( expiry ); } 

所以,我不知道该怎么做,因为’new Date()’不是一个静态的标准。

  1. 我不应该费心去测试’isValid’,只是分别测试’isLicenseStringValid()’和’getExpiryDate()’函数吗?
  2. 我是否只是在测试中使用许可证密钥,并且过期时间过长,以便在到期时切换作业?
  3. 我是否尝试将’new Date()’模拟为某些’getCurrentTime()’方法,以便我可以假装它现在是什么时间?

其他人通常对时间条件的测试做些什么?

绝对嘲笑new Date()

使用getCurrentTime()方法或类似方法创建Clock接口。 这样你可以有一个用于测试的FakeClock和一个使用System.currentTimeMillis()或其他的SystemClock

我已经多次这样做了 – 它运作得非常好。 这也是合乎逻辑的 – 有效地,您需要“当前时间服务”,因此应该像任何其他依赖项一样注入。

我通常会在测试代码中注入日期提供程序。 如果您需要切换约定或以其他方式“修复”时间测试代码,这也会有所帮助。

使用dependency injection并注入提供getExpiryDate()方法的getExpiryDate()

如果您认为TimeProvider / Clock抽象太过落实完美主义者(很可能就是这种情况),请考虑改为

使getCurrentType受保护虚拟,然后创建包含您发布的代码的ProductionType的TestingProductionType后代。 在该类型中,重写getCurrentType()方法以返回一些确定性结果。 在unit testing中,改为创建此TestingProductionType的实例。

Viola,当前时间的依赖性现已从您的unit testing中删除。 现在唯一没有经过unit testing的生产代码是一条返回新Date()的单行方法。 我可以忍受。

如果您可以访问http://research.microsoft.com/en-us/projects/pex/查看Moles allows to replace any .NET method with a delegate使用Moles allows to replace any .NET method with a delegate只需使用它来替换Date并让它返回您需要的任何内容。 那你就不需要做任何疯狂的事了。

-Raul

这三种方法都是可能的:

  1. 不要测试:懒人的方式
  2. 使用许可证,在你离开工作岗位之前,这个许可证不会过期:用我的方式掩盖
  3. 使用模拟作为当前日期,例如TimeProvider:完美主义者的方式

我要去做一个comprimise:我将当前日期作为参数添加到isExpired方法和isValid方法。 对于您的实时生产代码,添加一个简单的isValid()无参数覆盖,调用isValid(new Date()) 。 您的测试代码使用以当前日期为参数的版本。