10

我正在尝试编写一个测试来验证我下面的演员正在创建一个 heartBeatExpireWorker 和一个 heartBeatAccepter,但我不知道该怎么做。

首先,我想我可以使用 Mockhito mock 或 spy 代替 context,然后验证我调用了 actorOf,但我想不出一种在不破坏 Akka 测试框架的情况下注入上下文的方法。

然后,我想我可以向工作人员发送一条识别消息以验证他们是否存在。但在我看来,这也行不通,因为 Akka TestKit 似乎没有为被测演员创建子演员。它只能接收可以代表相邻参与者的测试探针。

class HeartBeatPumpWorker(chatService: ChatService, target: HeartBeatMessageCmd) extends Actor with ActorLogging with
WorkersReference {

  val heartBeatInterval = chatService.getHeartBeatInterval

  val tick = context.system.scheduler.schedule(0 millis, heartBeatInterval millis, self, SendHeartBeat(target))

  override def postStop() = tick.cancel()

  def receive = {
    case SendHeartBeat(command: HeartBeatMessageCmd) =>
      log.debug("Sending heartbeat")
      //Send heartbeat to GWT
      val userTarget = NetworkWorker.buildEventUserTarget(command.getEventCode, command.getUser)

      val uuid: String = UUID.randomUUID().toString
      val freshCommand = new HeartBeatMessageCmd(command.getUser, command.getEventCode, uuid, command.getUserSession)
      networkWorker ! NetworkBroadcast(userTarget, freshCommand)

      val heartBeatId: String = freshCommand.getUuid
      //create expirer
      val heartBeatExpireWorkerRef = context.actorOf(HeartBeatExpireWorker.props(chatService, freshCommand),
        HeartBeatExpireWorker.name(heartBeatId))
      val heartBeatAccepterRef = context
        .actorOf(HeartBeatAcceptWorker.props(chatService, freshCommand), HeartBeatAcceptWorker.name(heartBeatId))

      //record heartbeat
        chatService.saveSentHeartbeat(heartBeatId, freshCommand.getUserSession, freshCommand.getEventCode,
          freshCommand.getUser,
        freshCommand.getTimeCmdGenerated)
    case _ =>
      log.error("Pumper received unknown message.  This shouldn't happen " + sender.path.toString)
      self ! PoisonPill
  }

}


object HeartBeatPumpWorker {
  def name(eventCode: String, user: String, sessionId: String) = f"HeartBeatPumpWorker-$eventCode-$user-$sessionId"

  def path(eventCode: String, user: String, sessionId: String) : String = {
    EventWorker.Path + "/" + name(eventCode, user, sessionId)
  }

  def props(chatService: ChatService, heartBeatMsgCmd: HeartBeatMessageCmd) = {
    Props(classOf[HeartBeatPumpWorker], chatService, heartBeatMsgCmd)
  }
}
4

2 回答 2

16

我目前使用的技术是拦截actor创建并创建TestProbes。在我的演员中,我混合了一个单独的 ActorMaker 特征:

trait ActorMaker { this: Actor =>
  def makeActor(props: Props) = context.actorOf(props)
}

并使用它MyActor extends Actor with ActorMaker代替 context.actorOf。

对于测试,我有一个 TestProbeMaker 可以捕获所有创建的演员及其道具:

trait TestProbeMaker { this: Actor =>
  val probes = ListBuffer.empty[(Props, TestProbe)]
  def makeActor(props: Props) = { val probe = TestProbe()
    probes += (props -> probe)
    probe.ref
  }
}

我在测试时把它混进去

val actorUnderTest = TestActorRef(Props(new MyActor with TestProbeMaker))

这样我就可以准确地断言创建了哪些演员。我还可以使用probe.expectMsg断言消息已发送到那些创建的参与者。

要访问探针,请使用actorUnderTest.underlyingActor.asInstanceOf[TestProbeMaker]

于 2013-09-18T16:01:11.027 回答
3

在 parent 的构造函数中Props为子项(例如)注入。通过任何你想要的测试。让父母通过提供实例化孩子。与孩子互动。最后一部分取决于您的数据流。例如,如果父母将您与孩子屏蔽,但将消息委托给他们,则将消息发送给父母。如果孩子们互相交谈,请使用测试探针或类似的东西。HeartBeatAcceptWorker.propsHeartBeatPumpWorkerPropsProps

于 2013-09-04T07:42:51.357 回答