如何测试向另一个演员发送消息的Akka演员?

时间:2015-03-26 02:20:53

标签: scala akka scalatest akka-testkit

我正在使用ScalaTest与Akka TestKit为我编码的演员编写单元和集成测试,以简单地向另一个演员发送消息,而不会改变任何内部状态。以此为例:

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

我想编写一个测试,确认anotherActor处理AnotherMessageMyActor处理MyMessage TestActorRef。典型的例子是使用val testActorRef = TestActorRef(new MyActor) "MyActor" should "change some internal state when it receives MyMessage" in { testActorRef ! MyMessage testActorRef.underlyingActor.someState shouldBe "altered" } 来获取底层actor并检查一些应该在收到消息时受到影响的内部状态,如下所示:

TestProbe

但就我而言,我并不关心这种状态。事实上,我想避免持有任何这样的状态。 TestProbe.ref并不是我想要的,因为你仍然需要向被测试的演员注册一个{{1}}。在大多数情况下,我查看了有关测试的Akka文档中的所有示例(http://doc.akka.io/docs/akka/snapshot/scala/testing.html),但没有找到任何合适的例子。

1 个答案:

答案 0 :(得分:16)

可能有几种方法可以做到这一点,我会告诉你一个在我们有类似测试的东西时有效的方法。我仍然认为TestActorRefTestKitTestProbe是可行的方法。考虑以下结构:

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 _ =>
  }
}

问题在于您有一个actor实例创建一个子actor,并且作为测试的一部分,您需要确保该子项获得一条消息,即使您在测试中对该子项的创建没有任何控制权。当我们遇到这种情况时,我们会做如下的简单操作(使用specs2完成,但应该能够在ScalaTest中创建类似的东西):

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

关键在于,在创建要测试的actor时,我会覆盖创建子项的方法,以便提供我的探测器。它粗糙,但也简单而有效。