2016-08-20 1 views
2

Я пытаюсь проверить состояние переключения метода приема. Найдено this stackoverflow пост, но это также не ясно дает решение. Вы найдете ниже упрощенный фрагмент кода: -аккуратный способ тестирования стать небезопасным swtichover в scala

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 Finite State Machine] (http://doc.akka.io/docs/akka/current/scala/fsm.html) вместо попытки «запретить». –

ответ

0

StackOverflow сообщение, которое Вы упомянули содержит два предложили способы проверки вашего актера.

  1. Излучение государства переходит к другому актеру.
  2. Не тестируйте изменение состояния, но поведение актера.

В первом примере у вас есть способ отправить информацию из вашего актера при каждом изменении состояния. В Акке передача информации об изменении состояния в качестве сообщений актеров является естественным способом реализации этого.

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 является состоянием актера, который уведомляет данную ссылку актера каких-либо изменений состояния , Обратите внимание, что это не позволяет проверять текущее состояние, а вместо этого - журнал состояний. Кроме того, можно ввести ошибку в коде уведомления штата, потому что код уведомления вручную добавляется к актеру, а не актер делает это автоматически.

Я изменил стиль тестирования на 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 делает изменение состояния, но не уведомляет, когда его состояние изменилось. Вместо этого у него есть специальная команда для проверки интересных деталей о ее состоянии. В тесте мы отправляем несколько сообщений, которые вызывают изменения состояния актера аккумулятора. Наконец, мы проверяем результат этих сообщений, запрашивая аккумулятор.

Смежные вопросы