2016-08-04 7 views
4

Я пытаюсь получить пробный зонд для ответа с подтверждением, когда он получает какое-либо сообщение.Акка Тест актера: автоматический ответ с помощью TestProbe

Я написал следующий код в моем тесте, но он не работает:

val chgtWriter = new TestProbe(system) { 

      def receive: Receive = { 

      case m => println("receive messagereplying with ACK"); sender() ! ACK 

      } 

     } 

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

feature("The changeSetActor periodically fetch new change set following a schedule") { 


scenario("A ChangeSetActor fetch new changeset from a Fetcher Actor that return a full and an empty ChangeSet"){ 


    Given("a ChangeSetActor with a schedule of fetching a message every 10 seconds, a ChangeFetcher and a ChangeWriter") 

    val chgtFetcher = TestProbe() 

    val chgtWriter = new TestProbe(system) { 

     def receive: Receive = { 

     case m => println("receive message {} replying with ACK"); sender() ! ACK 

     } 

    } 
    val fromTime = Instant.now().truncatedTo(ChronoUnit.SECONDS) 
    val chgtActor = system.actorOf(ChangeSetActor.props(chgtWriter.ref, chgtFetcher.ref, fromTime)) 

    When("all are started") 


    Then("The Change Fetcher should receive at least 3 messages from the ChangeSetActor within 40 seconds") 

    var changesetSNum = 1 

    val received = chgtFetcher.receiveWhile(40 seconds) { 

     case FetchNewChangeSet(m) => { 

     println(s"received: FetchNewChangeSet(${m}") 

     if (changesetSNum == 1) { 
      chgtFetcher.reply(NewChangeSet(changeSet1)) 
      changesetSNum += 1 
      } 
      else 
      chgtFetcher.reply(NoAvailableChangeSet) 
     } 

     } 

    received.size should be (3) 

} 

}

changeSetActor полностью протестирована и работает. Тест зависает с ChangeWriter. Он никогда не получает сообщение в методе приема.

EDIT1 (После @Jakko Anser)

Auto Pilots выглядит следующим образом:

val probe = TestProbe() 
probe.setAutoPilot(new TestActor.AutoPilot { 
    def run(sender: ActorRef, msg: Any): TestActor.AutoPilot = 
    msg match { 
     case "stop" ⇒ TestActor.NoAutoPilot 
     case x  ⇒ **testActor.tell(x, sender)**; TestActor.KeepRunning 
    } 
}) 

Хотя все объяснение до сих пор путь понятно, что сбивает с толку в Официальным примером является ссылка «testActor». Кто здесь testActor? в этой точке нет объявления переменной этого имени.

ответ

3

Вы можете создать сценарий с помощью Auto Pilots. Например:

import akka.testkit._ 
val probe = TestProbe() 
probe.setAutoPilot(new TestActor.AutoPilot { 
    def run(sender: ActorRef, msg: Any): TestActor.AutoPilot = { 
    println("receive messagereplying with ACK") 
    sender ! ACK 
    TestActor.KeepRunning 
    } 
}) 

В приведенном выше примере, мы создали пробник с автоматическим обработчиком сообщений, Auto Pilot. Автоматический запуск автоматически срабатывает, когда зонд получает сообщение. В этом примере автопилот распечатает сообщение и ответит отправителю.

После того, как сообщение обработано, автопилот может решить, как будет обрабатываться следующее входящее сообщение. Он может либо настроить другой автопилот, повторно использовать существующий автопилот (TestActor.KeepRunning), либо полностью отключить автопилот (TestActor.NoAutoPilot). В этом примере один и тот же автопилот будет использоваться для обработки всех входящих сообщений.

Вы все равно можете использовать утверждения тестового зонда, как обычно, даже с автопилотом, прикрепленным к зонду.

testActor в официальной документации относится к субъекту, с которым вы пишите тесты. Например, в вашем случае актером может быть ChangeSetActor, присвоенный значению chgtActor. Поскольку все, что вы действительно хотите сделать, это ответить обратно отправителю с зонда, достаточно, чтобы автопилот тестового зонда ответил обратно отправителю и не заботился о testActor.

+0

Добавлен недостающий 'KeepRunning' и некоторые сведения о том, как его использовать. –

+0

У меня недостаточно комментариев, чтобы прокомментировать исходное сообщение, поэтому я просто добавлю свои комментарии здесь. 'target.tell (message, source)' почти эквивалентен 'target! message': оба отправляют сообщение «target». Разница заключается в том, что вы должны явно указывать отправителя сообщения с '.tell()', но с '!' Отправитель будет выбран неявно. Если вы вызываете '!' Внутри актера, актер будет использоваться в качестве отправителя. –

+0

Я отредактировал вопрос с обновлением из вашего ответа. Я думаю, вопрос здесь в том, почему вы используете отправителя! ACK вместо testActor.tell (ACK, отправитель).Я не знаю, что представляет переменная testActor в исходном примере. Самое главное, где это определено. – MaatDeamon