Scala和Akka-使用Akka Testkit将参与者作为一个系统进行测试

Scala和Akka-使用Akka Testkit将参与者作为一个系统进行测试,scala,unit-testing,akka,akka-testkit,Scala,Unit Testing,Akka,Akka Testkit,在Scala应用程序中,假设我有ActorA和ActorB。我想在ScalaTest中设计一个测试用例,它允许我向Actora发送一条消息,并查看它向ActorB发送了什么消息,以便查看a是否正确地处理了它的数据并向B发送了正确的消息。如何测试这一点?我自己花了很长时间才把这件事做好……但似乎大部分都奏效了 class A extends Actor { ... } class B extends Actor { ... } class C(p: TestProbe) extends B {

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

这是最好的方法吗?有更好的实践吗?

对我来说,听起来你想要的是单独测试演员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))
}
有其他方法可以将对actor B的引用传递给actor A,但是使用构造函数可以说是最简单的选择。在上面的例子中,我们还提供了一种为演员创建正确的
道具的方法

既然可以控制对actor B的引用,那么就可以在测试中用testprobe替换actor引用

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请求的entry actor到我们执行的整个(模拟的)服务调用链,并验证数据输出和web响应。一个挑战是获取异步行为,以便断言不需要排序。如果这能奏效,那就解决了。