Created
December 13, 2013 22:42
-
-
Save archie/7952671 to your computer and use it in GitHub Desktop.
Examples of testing Akka actor parent-child relationships, mostly based on findings from https://www.assembla.com/spaces/akka/tickets/3043#/activity/ticket:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package pc | |
import akka.actor.Actor | |
import akka.actor.Props | |
import akka.actor.ActorRef | |
import akka.actor.ActorRefFactory | |
class Parent extends Actor { | |
val child = context.actorOf(Props[Child], "child") | |
var ponged = false | |
def receive = { | |
case 'pingit => child ! 'ping | |
case 'pong => ponged = true | |
} | |
} | |
class Child extends Actor { | |
def receive = { | |
case 'ping => context.parent ! 'pong | |
} | |
} | |
class DependentChild(parent: ActorRef) extends Actor { | |
def receive = { | |
case 'ping => parent ! 'pong | |
} | |
} | |
class DependentParent(childProps: Props) extends Actor { | |
val child = context.actorOf(childProps, "child") | |
var ponged = false | |
def receive = { | |
case 'pingit => child ! 'ping | |
case 'pong => ponged = true | |
} | |
} | |
class GenericDependentParent(childMaker: ActorRefFactory => ActorRef) extends Actor { | |
val child = childMaker(context) | |
var ponged = false | |
def receive = { | |
case 'pingit => child ! 'ping | |
case 'pong => ponged = true | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package pc | |
import org.scalatest.WordSpec | |
import org.scalatest.Matchers | |
import akka.testkit.TestKitBase | |
import akka.actor.ActorSystem | |
import akka.actor.Props | |
import akka.actor.Actor | |
import akka.testkit.ImplicitSender | |
import akka.testkit.TestProbe | |
import akka.testkit.TestActorRef | |
import akka.actor.ActorRefFactory | |
class MockedChild extends Actor { | |
def receive = { | |
case 'ping => sender ! 'pong | |
} | |
} | |
class ParentChildSpec extends WordSpec with Matchers with TestKitBase { | |
implicit lazy val system = ActorSystem() | |
"A DependentChild" should { | |
"be tested without its parent" in { | |
val probe = TestProbe() | |
val child = system.actorOf(Props(classOf[DependentChild], probe.ref)) | |
probe.send(child, 'ping) | |
probe.expectMsg('pong) | |
} | |
} | |
"A DependentParent" should { | |
"be tested with custom props" in { | |
val probe = TestProbe() | |
val parent = TestActorRef(new DependentParent(Props[MockedChild])) | |
probe.send(parent, 'pingit) | |
// test some parent state change | |
parent.underlyingActor.ponged should (be(true) or be(false)) | |
} | |
} | |
"A GenericDependentParent" should { | |
"be tested with a child probe" in { | |
val probe = TestProbe() | |
val maker = (_: ActorRefFactory) => probe.ref | |
val parent = system.actorOf(Props(classOf[GenericDependentParent], maker)) | |
probe.send(parent, 'pingit) | |
probe.expectMsg('ping) | |
} | |
} | |
"A fabricated parent" should { | |
"test its child responses" in { | |
val proxy = TestProbe() | |
val parent = system.actorOf(Props(new Actor { | |
val child = context.actorOf(Props[Child], "child") | |
def receive = { | |
case x if sender == child => proxy.ref forward x | |
case x => child forward x | |
} | |
})) | |
proxy.send(parent, 'ping) | |
proxy.expectMsg('pong) | |
} | |
} | |
} |
Thank you for the example it's really helpful.
In line 37 in the test, I think you should wrap it in within(100 millis)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was very helpful. Thanks.
For testing that a child is sending to a parent, I also found the following pattern helpful. Passing in parent.ref to TestActorRef was the key.