【问题标题】:How do I test an Akka actor that sends a message to another actor?如何测试向另一个 Actor 发送消息的 Akka Actor?
【发布时间】:2015-05-29 23:18:50
【问题描述】:

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

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

我想编写一个测试来确认anotherActor 处理AnotherMessage 作为MyActor 处理MyMessage 的结果。经典的例子是使用TestActorRef 来获取底层actor并检查一些在收到消息时应该受到影响的内部状态,如下所示:

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

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

【问题讨论】:

    标签: scala akka scalatest akka-testkit


    【解决方案1】:

    可能有几种方法可以做到这一点,当我们有类似的测试时,我会向您展示一种有效的方法。我仍然认为TestActorRef、TestKit 和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时,我重写了创建子的方法以提供我的探针。它很粗糙,但也简单有效。

    【讨论】:

    • 正是我想要的!我什至没有想过用我可以重写的方法来创建子演员,以放入TestProbe.ref。谢谢@cmbaxter,
    • 如果我们在接收方法中创建了另一个actor,我们如何做到这一点?
    • 如何在 Java 中实现?
    猜你喜欢
    • 2013-04-30
    • 2021-09-11
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2015-12-09
    • 2018-07-17
    • 2017-06-29
    • 2013-11-27
    相关资源
    最近更新 更多