3

在我的 Scala 应用程序中说我有 ActorA和 Actor B。我想在 ScalaTest 中设计一个测试用例,允许我向 Actor 发送消息A并查看它发送给 ActorB的消息,以便查看是否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]
  }
}

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

4

1 回答 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))
}

有其他方法可以将actor B 的引用传递给actor 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 的演员系统创建了演员,而不是使用TestActorRef. 这意味着actor消息处理将是异步的而不是同步的。就个人而言,我发现异步测试风格更适合,因为它更好地代表了演员在生产系统中的运行方式。官方文档中也推荐了异步测试

于 2016-08-08T21:45:23.370 回答