8

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

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

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

4

1 回答 1

16

可能有几种方法可以做到这一点,当我们有类似的测试时,我会向您展示一种有效的方法。我仍然认为TestActorRefTestKit并且TestProbe是要走的路。考虑以下结构:

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 实例,作为测试的一部分,您需要确保子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时,我重写了创建子的方法以提供我的探针。它很粗糙,但也简单有效。

于 2015-03-26T14:01:57.520 回答