在 scala 中模拟函数调用以进行单元测试



我想为函数编写一个单元测试

import com.github.nscala_time.time.Imports.{DateTime, richReadableInstant}
def myFunction(ts: Long):Long = {
(new DateTime(ts) to DateTime.now()).toDurationMillis
}

是否可以以某种方式模拟 Datetime.now(),以便测试结果不依赖于测试何时运行?

据我所知,这个库是围绕joda-time的包装器(正如官方文档所建议的那样,应该放弃它以支持java.time,但我假设你有一些约束迫使你在 Java 8 之前的版本上工作)。

joda-time附带了一系列静态帮助程序,除其他外,这些帮助程序允许您管理方法请求"当前时间"时的响应(在此处查看其JavaDoc)。

最简单的方法(但由于它所依赖的共享可变状态,可能容易出错)如下所示:

import com.github.nscala_time.time.Imports.{DateTime, richReadableInstant}
import org.joda.time.DateTimeUtils
DateTimeUtils.setCurrentMillisFixed(42)
def myFunction(ts: Long):Long = {
(new DateTime(ts) to DateTime.now()).toDurationMillis
}
assert(myFunction(42) == 0)

你可以在Scastie上玩这个代码。

如前所述,这种方法有点笨拙,并且依赖于共享的可变状态,这使得它容易出现令人困惑的错误。您可以构建一个不错的小助手,以确保您可以在特定测试中使用自定义时钟,并在完成后重置为系统时钟。所需的同步意味着性能下降,但对于测试来说可能是可以接受的。

import com.github.nscala_time.time.Imports.{DateTime, richReadableInstant}
import org.joda.time.DateTimeUtils
import org.joda.time.DateTimeUtils.MillisProvider
def myFunction(ts: Long):Long = {
(new DateTime(ts) to DateTime.now()).toDurationMillis
}
final class FixedClock(at: Long) extends MillisProvider {
override def getMillis(): Long = at
}
def withCustomClock[A](clock: MillisProvider)(f: => A): A = {
synchronized {
try {
DateTimeUtils.setCurrentMillisProvider(clock)
f
} finally {
DateTimeUtils.setCurrentMillisSystem() // _always_ reset to the system clock once done
}
}
}
assert(myFunction(42) > 1000000)
withCustomClock(new FixedClock(at = 42)) {
assert(myFunction(42) == 0)
Thread.sleep(1000)
assert(myFunction(42) == 0)
}
assert(myFunction(42) > 1000000)

您可以在 Scastie 上的另一个工作表上使用另一个示例。

相关内容

  • 没有找到相关文章

最新更新