I expanded the example from http://doc.akka.io/docs/akka/snapshot/scala/testing.html#Using_Multiple_Probe_Actors.
import akka.actor._
import akka.testkit.{TestProbe, TestKit}
import org.scalatest.{Suites, BeforeAndAfter, BeforeAndAfterAll, FlatSpecLike}
import scala.concurrent.duration._
class TestProbesTestSuites extends Suites(new TestProbesTest)
class TestProbesTest extends TestKit(ActorSystem("TestProbesTestSystem")) with FlatSpecLike with BeforeAndAfterAll with BeforeAndAfter {
override def afterAll: Unit = {
TestKit.shutdownActorSystem(system)
}
"A TestProbeTest" should "test TestProbes" in {
val actorRef = system.actorOf(Props[TestActor], "TestActor")
val tester1 = TestProbe()
val tester2 = TestProbe()
Thread.sleep(500.milliseconds.toMillis)
actorRef ! (tester1.ref, tester2.ref)
// When you comment the next line the test fails
tester1.expectMsg(500.milliseconds, "Hello")
tester2.expectMsg(500.milliseconds, "Hello")
// Alternative test
// Thread.sleep(500.milliseconds.toMillis)
// tester1.expectMsg(0.milliseconds, "Hello")
// tester2.expectMsg(0.milliseconds, "Hello")
()
}
}
class TestActor extends Actor with ActorLogging {
override def receive: Receive = {
case (actorRef1: ActorRef, actorRef2: ActorRef) => {
// When you change the schedule time in the next line to 100.milliseconds the test fails
context.system.scheduler.scheduleOnce(400.milliseconds, actorRef1, "Hello")(context.system.dispatcher)
context.system.scheduler.scheduleOnce(800.milliseconds, actorRef2, "Hello")(context.system.dispatcher)
}
case x => log.warning(x.toString)
}
}
I do not think that this a correct or good usage for a test.
When I remove the tester1.expectMsg(500.milliseconds, "Hello")
the test fails,
so testing of tester2 dependes on testing tester1. In my opinion this bad.
Also changing line context.system.scheduler.scheduleOnce(400.milliseconds, actorRef1, "Hello")(context.system.dispatcher)
to a delay of 100 milliseconds let the test fail. So testing message 2 depends on sending message 1. In my opinion this is bad, too.
To solve this I would add a Thread.sleep after sending the message and change the wait time for both #expectMsg to 0 milliseconds. Thread.sleep does also not look good for me in tests, but I think it is a must in actor testing. Is this the right way?
I thought TestProbe is made for testing multiple actors. But for me the wait time parameter of #expectMsg is quite useless, when testing multiple actors.
Any remarks are welcome.
tester2
to be received in 800 milliseconds then it's always going to fail if you expect it to be received in 500 milliseconds. It just happens to work because the first assertion causes a wait of 400ms beforehand. – cmbaxter