You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala中如何简便Mock java.time类调用?求类似Jest的时间模拟方案

在Scala中Mock java.time时间API的方案

1. 依赖注入Clock(推荐的标准方案)

java.time包的LocalDateTime.now()等方法默认使用系统时钟,我们可以通过依赖注入Clock来实现时间Mock,这是最贴合Java时间API设计的方式:

// 业务代码中依赖Clock,而非直接调用无参的now()
class TimeDependentService(clock: Clock = Clock.systemDefaultZone()) {
  def getCurrentTime(): LocalDateTime = LocalDateTime.now(clock)
}

// 测试时传入固定时钟
import java.time.{Clock, LocalDateTime, ZoneId}

val fixedInstant = LocalDateTime.of(2024, 5, 20, 14, 30).atZone(ZoneId.systemDefault()).toInstant()
val fixedClock = Clock.fixed(fixedInstant, ZoneId.systemDefault())

val service = new TimeDependentService(fixedClock)
assert(service.getCurrentTime() == LocalDateTime.of(2024, 5, 20, 14, 30))

// 也可以创建可调整的时钟,模拟时间流逝
val adjustableClock = Clock.tick(fixedClock, java.time.Duration.ofHours(1))

2. 自定义时间提供者Trait

如果需要更灵活的时间控制(比如批量调整时间),可以封装一个时间提供者Trait,在测试时替换实现:

trait TimeProvider {
  def now(): LocalDateTime
  def advanceBy(duration: java.time.Duration): Unit // 可选:添加时间推进方法
}

// 生产环境实现
class SystemTimeProvider extends TimeProvider {
  override def now(): LocalDateTime = LocalDateTime.now()
  override def advanceBy(duration: java.time.Duration): Unit = () // 生产环境无操作
}

// 测试环境Mock实现
class MockTimeProvider(var currentTime: LocalDateTime) extends TimeProvider {
  override def now(): LocalDateTime = currentTime
  override def advanceBy(duration: java.time.Duration): Unit = {
    currentTime = currentTime.plus(duration)
  }
}

// 业务代码中注入TimeProvider
class OrderService(timeProvider: TimeProvider) {
  def createOrder(): Order = Order(createdAt = timeProvider.now())
}

// 测试示例
val fixedTime = LocalDateTime.of(2024, 5, 20, 10, 0)
val mockProvider = new MockTimeProvider(fixedTime)
val service = new OrderService(mockProvider)

assert(service.createOrder().createdAt == fixedTime)
mockProvider.advanceBy(java.time.Duration.ofDays(1))
assert(service.createOrder().createdAt == fixedTime.plusDays(1))

3. 使用Mockito Mock静态方法(不推荐,仅用于遗留代码)

如果无法修改现有代码(必须直接MockLocalDateTime.now()静态调用),可以使用Mockito-inline来Mock静态方法:

import org.mockito.Mockito._
import java.time.LocalDateTime

// 启用静态Mock
val mockStatic = mockStatic(classOf[LocalDateTime])
when(LocalDateTime.now()).thenReturn(LocalDateTime.of(2024, 1, 1, 12, 0))

// 执行需要测试的代码,此时调用LocalDateTime.now()会返回固定值

// 验证调用并清理Mock
verifyStatic(classOf[LocalDateTime], times(1))
LocalDateTime.now()
mockStatic.close()

注意:静态Mock容易导致测试污染,需要确保每个测试用例都正确清理,仅在无法重构代码时使用。

内容的提问来源于stack exchange,提问作者Miguel Salas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:22:53