如何测试向另一个演员发送消息的 Akka 演员?
How do I test an Akka actor that sends a message to another actor?
我正在使用 ScalaTest 和 Akka TestKit 为我编码的演员编写单元和集成测试,以便在不改变任何内部状态的情况下简单地向另一个演员发送消息。以此为例:
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
也不是我想要的,因为您仍然需要向被测演员注册 TestProbe.ref
。在大多数情况下,我查看了 Akka 文档中有关测试的所有示例 (http://doc.akka.io/docs/akka/snapshot/scala/testing.html),但没有找到任何合适的示例。
可能有几种方法可以做到这一点,我将向您展示一种在我们有类似测试的情况下有效的方法。我仍然认为 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 _ =>
}
}
问题是您有一个创建 child 演员的演员实例,作为测试的一部分,您需要确保 child 收到消息,即使您在测试中没有收到消息在 child 的创建过程中没有任何控制权。当我们遇到这种情况时,我们会做如下简单的事情(使用 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 时,我覆盖了创建 child 的方法以提供我的探测。它很粗糙,但也简单有效。
我正在使用 ScalaTest 和 Akka TestKit 为我编码的演员编写单元和集成测试,以便在不改变任何内部状态的情况下简单地向另一个演员发送消息。以此为例:
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
也不是我想要的,因为您仍然需要向被测演员注册 TestProbe.ref
。在大多数情况下,我查看了 Akka 文档中有关测试的所有示例 (http://doc.akka.io/docs/akka/snapshot/scala/testing.html),但没有找到任何合适的示例。
可能有几种方法可以做到这一点,我将向您展示一种在我们有类似测试的情况下有效的方法。我仍然认为 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 _ =>
}
}
问题是您有一个创建 child 演员的演员实例,作为测试的一部分,您需要确保 child 收到消息,即使您在测试中没有收到消息在 child 的创建过程中没有任何控制权。当我们遇到这种情况时,我们会做如下简单的事情(使用 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 时,我覆盖了创建 child 的方法以提供我的探测。它很粗糙,但也简单有效。