【问题标题】:How to test that Akka actor was created in Scala如何测试 Akka 演员是在 Scala 中创建的
【发布时间】:2013-09-03 23:07:07
【问题描述】:

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

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

然后,我想我可以向工作人员发送识别消息以验证他们是否存在。但我突然想到这也行不通,因为 Akka TestKit 似乎没有为被测演员创建子演员。它只能接收可以代替相邻actors的Testprobes。

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)
  }
}

【问题讨论】:

    标签: scala akka scalatest testkit


    【解决方案1】:

    我目前使用的技术是拦截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]

    【讨论】:

    • 嗨,这看起来不错。但目前尚不清楚如何访问 TestProbe。在您的测试类中,您如何访问“探针”列表,因为它是在创建您的被测演员时混合的一个字段?我想你没有代码示例?
    • @C0deAttack 您可以通过将actorUnderTest.underlyingActor 强制转换为 TestProbeMaker 来访问探测器列表。
    【解决方案2】:

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

    【讨论】:

    • 我不确定我是否遵循。我需要在接收方法中定义 Props,因为我正在使用传入参数来定义我新生成的 heartBeatExpireWorkerRef 和 heartBeatAccepterRef 的路径。所以我不认为我可以注入道具。
    • 那么你需要通过消息注入它们。作为最后的手段,您可以通过消息为孩子注入名字,然后使用ActorSelection 查找孩子。这有帮助吗?
    • 听起来不错,但是 Akka TestKit 允许演员制作儿童演员吗?到目前为止,我发现的所有示例都只允许参与者与测试探针交互。我还没有找到任何示例测试,其中被测演员创建子演员。你知道我在哪里可以找到这样的示例测试吗?
    • 我不确定我理解你的意思。被测Actor只是一个Actor。看看fault tolerance chapter,也许会有帮助。
    猜你喜欢
    • 2014-03-09
    • 2016-02-03
    • 2018-05-23
    • 2021-02-11
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    相关资源
    最近更新 更多