2015-03-26 5 views
8

Ich benutze ScalaTest mit dem Akka TestKit, um Einheits- und Integrationstests für einen Akteur zu schreiben, den ich codiert habe, um einfach eine Nachricht an einen anderen Akteur zu senden, ohne einen internen Zustand zu verändern. Nehmen Sie dies zum Beispiel:Wie teste ich einen Akka-Schauspieler, der eine Nachricht an einen anderen Schauspieler sendet?

class MyActor extends Actor { 
    val anotherActor = context.actorOf(Props[AnotherActor]) 
    def receive: Receive = { 
    case MyMessage => anotherActor ! AnotherMessage 
    } 
} 

ich einen Test schreiben möchten, die bestätigt, dass anotherActorAnotherMessage als Folge der MyActor Verarbeitung MyMessage verarbeitet. Das klassische Beispiel ist TestActorRef zu verwenden, bei dem zugrunde liegenden Schauspieler zu bekommen und für einige interne Zustand zu überprüfen, die wie so bei Empfang der Nachricht betroffen sind, sollten:

val testActorRef = TestActorRef(new MyActor) 
"MyActor" should "change some internal state when it receives MyMessage" in { 
    testActorRef ! MyMessage 
    testActorRef.underlyingActor.someState shouldBe "altered" 
} 

Aber in meinem Fall habe ich kümmern sich nicht um solchen Zustand. Tatsächlich möchte ich vermeiden, einen solchen Staat zu halten. TestProbe war nicht ganz das, wonach ich gesucht habe, da Sie immer noch einen TestProbe.ref mit dem zu testenden Aktor registrieren müssen. Zum größten Teil habe ich alle Beispiele in der Akka-Dokumentation zum Testen (http://doc.akka.io/docs/akka/snapshot/scala/testing.html) betrachtet, aber nichts passendes gefunden.

Antwort

14

Es gibt wahrscheinlich ein paar Möglichkeiten, dies zu tun, ich werde Ihnen eine zeigen, die funktioniert, wenn wir etwas Ähnliches zum Test haben. Ich denke immer noch TestActorRef, TestKit und TestProbe sind der Weg zu gehen. Betrachtet man die folgende Struktur:

case object MyMessage 
case object AnotherMessage 

class MyActor extends Actor { 
    val anotherActor = createAnother 
    def receive: Receive = { 
    case MyMessage => anotherActor ! AnotherMessage 
    } 

    def createAnother = context.actorOf(Props[AnotherActor]) 
} 

class AnotherActor extends Actor{ 
    def receive = { 
    case _ => 
    } 
} 

Das Problem ist, dass man einen Schauspieler Beispiel ein Kind Schauspieler und als Teil Ihres Tests Erstellen Sie müssen sicherstellen, dass Kind eine Nachricht, auch wenn Sie in Ihrem Test wird nicht habe irgendeine Kontrolle bei der Erschaffung dieses Kindes. Wenn wir diese Situation haben, tun wir etwas Einfaches wie die folgende (done mit specs2, aber sollte etwas sein können ähnlich in ScalaTest erstellen):

import akka.actor._ 
import akka.testkit._ 
import org.specs2.mutable.SpecificationLike 
import org.specs2.runner.JUnitRunner 
import org.junit.runner.RunWith 

class MessageSendingSpec extends TestKit(ActorSystem("test")) with SpecificationLike{ 

    val probe = TestProbe() 
    val myActor = TestActorRef(new MyActor{ 
    override def createAnother = probe.ref 
    }) 


    "Sending MyMessage to an instance of MyActor" should{ 
    "pass AnotherMessage to the child AnotherActor" in { 
     myActor ! MyMessage 
     probe.expectMsg(AnotherMessage) 
     success 
    } 
    } 
} 

Der Schlüssel gibt also beim Erstellen der Schauspieler zu testen, ich überschreiben Sie die Methode, die das Kind erstellt, um meine Probe zu liefern. Es ist grob, aber auch einfach und effektiv.

+0

Genau das, was ich gesucht habe! Ich habe nicht einmal daran gedacht, Kinderakteure mit einer Methode zu kreieren, die ich einfach außer Kraft setzen könnte, um sie in 'TestProbe.ref' fallen zu lassen. Danke @cmbaxter, – nmurthy

+0

Wie machen wir das, wenn wir einen anderen Akteur innerhalb der Empfangsmethode haben? –

+0

Wie könnte das in Java implementiert werden? –

Verwandte Themen