Scala和Akka - 使用Akka Testkit测试演员系统

3

在我的Scala应用程序中,假设我有Actor A和Actor B。我想设计一个ScalaTest测试用例,使我能够向Actor A发送一条消息,并查看它发送到Actor B的消息,以便查看A是否正确处理其数据并将正确的消息发送至B。如何进行测试?对此,我自己思考了很长时间...但它似乎大部分工作都已经完成了。

class A extends Actor { ... }

class B extends Actor { ... }

class C(p: TestProbe) extends B {
  override def receive = {
    LoggingReceive {
      case x =>
        println(x.toString)
        p.ref ! x
    }
  }
}

case class MsgToB(...)

// Spec class which extends TestKit
"A" should {
  "send the right message to B" {
    val p = TestProbe()
    val a = TestActorRef[A]
    val c = TestActorRef(Props(new C(p)))

    // Assume A has a reference to C. Not shown here.
    a ! msg
    // Assert messages
    p.expectMsgType[MsgToB]
  }
}

这是最好的方法吗?有更好的做法吗?

1个回答

1
对我来说,你想要的是在隔离环境中测试演员A的行为。为了做到这一点,您需要能够控制演员A如何获取对演员B的引用。例如,您可以在演员的构造函数中提供该引用:
import akka.actor.{Actor, ActorRef, Props}

class A(refToB: ActorRef) extends Actor { ... }

object A {
  def props(refToB: ActorRef): Props = Props(new A(refToB))
}

有其他方法可以将对B演员的引用传递给A演员,但使用构造函数可能是最简单的选择。在上面的示例中,我们还提供了一种创建正确的Props的方法。

现在,您可以控制对B演员的引用,在测试中将演员引用替换为测试探针。

import akka.testkit.TestProbe

// Initialise a test probe
val probe = TestProbe()

// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))

// Send a message to actor A
a ! someMessage

// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]

请注意,我使用了来自TestKit的actor系统创建了actor,而不是使用TestActorRef。这意味着actor消息处理将是异步的,而不是同步的。个人而言,我发现异步测试风格更加适合,因为它更好地代表了演员在生产系统中运行的方式。官方文档也推荐使用异步测试

我喜欢这个。我选择了原始实现,因为我必须做些什么,但这听起来很有趣。目标是测试整个演员系统,从处理Web请求的入口演员到我们进行的整个(模拟的)服务调用链,并验证数据输出以及Web响应。一个挑战是获得异步行为,以便断言不需要排序。如果这样可以解决问题。 - Rig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接