Как проверить, что актер Akka был создан в Scala
Я пытаюсь написать тест, который проверит, что мой актер ниже создает heartBeatExpireWorker и heartBeatAccepter, но я понятия не имею, как это сделать.
Сначала я подумал, что мог бы использовать Mockhito mock или spy вместо контекста, а затем проверить, что я вызвал 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)
}
}
2 ответа
Впрыскивать Props
для детей (например, HeartBeatAcceptWorker.props
) в конструкторе родителя HeartBeatPumpWorker
, Пройти любой Props
Вы хотите от теста. Пусть родительский экземпляр детей через предоставленный Props
, Взаимодействовать с детьми. Последняя часть зависит от вашего потока данных. Например, если родитель защищает вас от детей, но делегирует им сообщения, отправьте сообщение родителю. Если дети разговаривают друг с другом, используйте тестовые зонды или что-то подобное.
В настоящее время я использую технику, чтобы перехватить создание актера и создать 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]