2013-09-03 11 views
10

Próbuję napisać test, który sprawdzi, czy mój aktor poniżej tworzy heartBeatExpireWorker i heartBeatAcepter, ale nie mam pojęcia, jak to zrobić.Jak przetestować, że aktor Akka został utworzony w Scali

Po pierwsze pomyślałem, że mógłbym użyć makiety Mockhito lub szpiega zamiast kontekstu, a następnie zweryfikować, czy nazwałem actorOf, ale nie mogę wymyślić sposobu na wstrzyknięcie kontekstu bez łamania schematu testowania Akka.

Potem pomyślałem, że mogę wysłać wiadomość identyfikacyjną do pracowników, aby sprawdzić, czy istnieją. Ale przyszło mi do głowy, że to też nie zadziała, ponieważ Akka TestKit nie wydaje się tworzyć dzieci aktorów aktora w teście. Potrafi tylko przyjmować pakiety testowe, które mogą stać na sąsiednich aktorów.

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

Odpowiedz

3

wstrzyknąć Props dla dzieci (np HeartBeatAcceptWorker.props) w konstruktora rodzica HeartBeatPumpWorker. Przełóż dowolną liczbę z testu na Props. Pozwól rodzicowi utworzyć dzieci, podając Props. Interakcja z dziećmi. Ostatnia część zależy od przepływu danych. Na przykład, jeśli rodzic chroni cię przed dziećmi, ale przekazuje im wiadomości, wyślij wiadomość do rodzica. Jeśli dzieci rozmawiają ze sobą, użyj sond testowych lub czegoś podobnego.

+0

Nie jestem pewien, czy podążam. Muszę zdefiniować rekwizyty w metodzie receive, ponieważ używam argumentu przychodzącego, aby zdefiniować ścieżkę dla nowo wygenerowanego heartBeatExpireWorkerRef i heartBeatAccepterRef. Więc nie sądzę, żebym mógł wstrzyknąć rekwizyty. – HappyCoder86

+1

Cóż, musisz wprowadzić je za pomocą wiadomości. W ostateczności można wprowadzić nazwisko dziecka za pomocą wiadomości, a następnie sprawdzić dziecko za pomocą "ActorSelection". To pomaga? – agilesteel

+0

Brzmi nieźle, ale czy Akka TestKit pozwala aktorowi na tworzenie aktorów dziecięcych? Wszystkie przykłady, które do tej pory znalazłem, pozwalają aktorowi na interakcję z sondami testowymi. Nie znalazłem żadnych przykładowych testów, w których testowany aktor tworzy dzieci. Czy wiesz, gdzie mogę znaleźć przykładowy test? – HappyCoder86

13

Technika, której obecnie używam, polega na przechwytywaniu tworzenia aktorów i tworzeniu zestawów testowych. W moich aktorów mieszać w oddzielnym cechy ActorMaker:

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

i używać go w MyActor extends Actor with ActorMaker zamiast context.actorOf.

Dla testów mam TestProbeMaker który przechwytuje wszystkie stworzone aktorów i ich rekwizyty:

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

I zmieszać go w trakcie badań

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

ten sposób mogę dochodzić dokładnie jakie aktorów są tworzone. Mogę również użyć sondy.expectMsg, aby potwierdzić, że wiadomości są wysyłane do stworzonych aktorów.

Aby uzyskać dostęp do sond, użyj actorUnderTest.underlyingActor.asInstanceOf[TestProbeMaker]

+0

Cześć, to wydaje się miłe. Ale nie jest jasne, w jaki sposób można uzyskać dostęp do TestProbe. W twojej klasie testowej, w jaki sposób uzyskujesz dostęp do listy "sond", biorąc pod uwagę, że jest to pole zmieszane podczas tworzenia aktora w teście? Nie sądzę, że masz przykład kodu? – C0deAttack

+0

@ C0deAttack można dostać się do listy sond za pomocą 'actorUnderTest.underlyingActor', przesyłając ją do TestProbeMaker. – Andrejs

Powiązane problemy