2016-08-20 83 views
2

我想测试状态切换的接收方法。 发现this stackoverflow后,但也没有明确给出解决方案。 请从下面简化代码片段: -整洁的方式来测试成为不可能swtichover在斯卡拉

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

考虑使用[Akka有限状态机](http://doc.akka.io/docs/akka/current/scala/fsm.html)而不是尝试“不成功”。 –

回答

0

的StackOverflow上发布你提到有两个建议的方法来测试你的演员。

  1. 将状态更改发送给其他参与者。
  2. 不要测试状态改变,而是测试参与者的行为。

在第一个示例中,您可以通过某种方式在每次状态更改时从您的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自动执行的。

我将测试样式更改为asynchronous testing style以获得更真实的测试。

状态更改通知允许您获取有关参与者转换到的具体状态的信息,但它不会告诉您它是否按照应有的方式工作。而不是测试演员经历的状态变化,而是测试演员本身的行为。

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确实状态的变化,但是当它的状态已经改变不通知。相反,它有一个特定的获取命令来检查有关它的状态的有趣部分。在测试中,我们发送多个消息,导致累加器参与者发生状态变化。最后,我们通过查询累加器来检查这些消息的结果。