在akka中测试计时器事件

nor*_*gon 7 testing unit-testing scala akka

我有一个函数scheduleOnce用于安排事件在将来某个时间发生,我想编写一个测试来检查:

  • 事件确实已经安排好了
  • 它安排在正确的时间
  • 当该事件最终触发时,系统按预期运行

但是我不希望测试实际上等几分钟什么都不做.

我应该如何最好地测试使用akka的Scheduler的代码?

cmb*_*ter 5

这是@lmm描述的模拟调度程序的示例。在此示例中,我们确实将动作的完整调度和处理作为两个单独的场景进行测试。给定条件的第一个测试(在我的示例中接收到某种类型的消息),我们将安排一个回调,第二个是当计时器关闭时处理返回到自身的消息的处理。代码如下:

object TimerExampleActor{
  case object ClearState
  case class ScheduleStateClearing(duration:FiniteDuration)
}

class TimerExampleActor extends Actor{
  import TimerExampleActor._

  var state:List[Int] = Nil

  def receive = {
    case ScheduleStateClearing(d) =>
      scheduler.scheduleOnce(d, self, ClearState)(context.dispatcher)

    case ClearState => 
      state = Nil
  }

  def scheduler = context.system.scheduler
}
Run Code Online (Sandbox Code Playgroud)

然后,使用specs2和mockito,我的测试用例如下:

class TimerExampleActorTest extends Specification with Mockito with NoTimeConversions{
  import TimerExampleActor._
  implicit val system = ActorSystem("test")

  trait testscope extends Scope{
    val mockScheduler = mock[Scheduler]
    val actor = TestActorRef(new TimerExampleActor{
      override def scheduler = mockScheduler 
    })
  }

  "A request to schedule state clearing" should{
    "schedule a callback for the message ClearState to self with the supplied duration" in new testscope{
      val dur = 1.minute
      actor ! ScheduleStateClearing(dur) 
      there was one(mockScheduler).scheduleOnce(dur, actor, ClearState)(actor.underlyingActor.context.dispatcher)      
    }
  }

  "A ClearState message received by the actor" should{
    "clear the interval 'state' List" in new testscope{
      actor.underlyingActor.state = List(1,2,3)
      actor ! ClearState
      actor.underlyingActor.state mustEqual Nil
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以看到,当我创建被测试的actor实例时,我将覆盖为获取调度程序实例而创建的方法,从而允许我返回模拟。这不是进行此类测试的唯一方法,但是它当然可以作为您考虑的一种选择。