我正在尝试测试接收方法的状态切换。 找到this stackoverflow帖子,但这也没有明确给出解决方案。 请在下面找到简化的代码段: -
package become_unbecome_basics
import akka.actor.{Actor, ActorSystem}
import akka.testkit.{ImplicitSender, TestActorRef, TestKit}
import become_unbecome_basics.BasicBecomeUnbecomeActor.{SWITCH_TO_MASTER, SWITCH_TO_STANDBY}
import com.typesafe.scalalogging.LazyLogging
import org.scalatest.FlatSpecLike
import org.scalatest.Matchers._
class BecomUnbecomeSwitchoverTest extends TestKit(ActorSystem("testSystem")) with ImplicitSender with FlatSpecLike{
"initially receive" should "points to master" in {
val aRef = TestActorRef[BasicBecomeUnbecomeActor]
val actor = aRef.underlyingActor
//not sure, weather we have something like this to assert
//actor.receive should be(actor.master)
}
}
object BasicBecomeUnbecomeActor{
case object SWITCH_TO_MASTER
case object SWITCH_TO_STANDBY
}
class BasicBecomeUnbecomeActor extends Actor with LazyLogging{
override def receive: Receive = master
def master: Receive = {
case SWITCH_TO_STANDBY =>
context.become(standBy)
case msg => logger.debug(s"master : $msg received")
}
def standBy: Receive = {
case SWITCH_TO_MASTER =>
context.unbecome()
case msg => logger.debug(s"standBy : $msg received")
}
}
答案 0 :(得分:0)
您提到的StackOverflow帖子包含两种测试演员的方法。
在第一个示例中,您可以通过某种方式在每次状态更改时向您的actor发送信息。在Akka中,将状态更改信息作为actor消息发送是实现此目的的自然方式。
import akka.actor._
import akka.testkit._
class ExampleActor(notify: ActorRef) extends Actor with ActorLogging {
import ExampleActor.{Master, StandBy}
def receive: Receive = master
def master: Receive = {
case StandBy =>
notify ! StandBy
context.become(standby)
case msg =>
log.debug("received msg in master: {}", msg)
}
def standby: Receive = {
case Master =>
notify ! Master
context.become(master)
case msg =>
log.debug("received msg in standby: {}", msg)
}
}
object ExampleActor {
def props(notify: ActorRef): Props = Props(new ExampleActor(notify))
case object Master
case object StandBy
}
class ExampleActorTest extends TestKit(ActorSystem("testSystem")) with FlatSpecLike {
"ExampleActor" should "move to stand by state" in {
val probe = TestProbe()
val actor = system.actorOf(ExampleActor.props(probe.ref))
actor ! ExampleActor.StandBy
probe.expectMsg(ExampleActor.StandBy)
}
}
(我还没有运行代码,所以对代码中的任何错误表示歉意)
在上面的代码中,ExampleActor
是一个有状态的actor,它通知给定的actor引用任何状态的变化。请注意,这不允许检查当前状态,而是检查状态转换的日志。此外,可以在状态通知代码中引入错误,因为通知代码是手动添加到actor而不是自动执行的操作。
我将测试样式更改为asynchronous testing style以获得更真实的测试。
状态更改通知允许您获取有关actor转换到的具体状态的信息,但它不会告诉您它是否按照应有的方式工作。不是测试演员经历的状态变化,而是如何测试演员本身所做的事情。
class Accumulator extends Actor with ActorLogging {
import Accumulator._
def receive: Receive = accumulatorReceive(0)
def accumulatorReceive(x: Int): Receive = {
case Add(i) => next(x + i)
case Remove(i) => next(x - i)
case Multiply(i) => next(x * i)
case Divide(i) => next(x / i)
case Get => sender() ! x
}
def next(x: Int) = context.become(accumulatorReceive(x))
}
object Accumulator {
def props: Props = Props(new Accumulator)
case class Add(i: Int)
case class Remove(i: Int)
case class Multiply(i: Int)
case class Divide(i: Int)
case object Get
}
class AccumulatorTest extends TestKit(ActorSystem("testSystem")) with FlatSpecLike {
import Accumulator._
"Accumulator" should "accumulate" in {
val probe = TestProbe()
val actor = system.actorOf(Accumulator.props)
actor ! Add(3)
actor ! Remove(1)
actor ! Multiply(4)
actor ! Divide(2)
probe.send(actor, Get)
probe.expectMsg(5)
}
}
在此示例中,Accumulator
执行状态更改,但在状态发生更改时不会通知。相反,它有一个特定的get命令,用于检查有关其状态的有趣部分。在测试中,我们发送多条消息,这些消息会导致累加器actor中的状态发生变化。最后,我们通过查询累加器来检查这些消息的结果。