Строгий режим для зондов Akka TestKit

Я пишу тестовый пример для приложения на основе актера. Один из компонентов можно приблизительно определить следующим образом:

class MyActor(a: ActorRef, b: ActorRef) extends Actor {
    override def receive: Receive = {
        case _ => 
            a ! "Got message!"
            b ! "Hello!"
    }
}

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

val a = TestProbe()
val b = TestProbe()
val c = system.actorOf(Props(new MyActor(a.testActor, b.testActor)))

c ! "Message!"
a.expectMsg("Got message!")

Теперь проблема в том, что тестовый пример проходит успешно, даже несмотря на то, что сообщение, отправленное b, не ожидалось и, следовательно, не было проверено.

Я знаю, что я могу вызвать b.expectNoMsg() в начале тестового случая, который позаботится об этой конкретной проблеме, но почему-то я считаю, что это не совсем масштабируемый подход (мне пришлось бы добавлять его каждый раз после всех ожидаемых вызовов, что довольно громоздко).

Итак, мой вопрос: есть ли возможность запускать akka-testkit в строгом режиме, чтобы каждое сообщение приходилось как-то ожидать? Предпочтительным способом является конфигурация TestKit, ActorSystem или TestProbe, но подойдет любое решение, которое не требует изменения каждого тестового примера (поэтому вызов expectNoMsg() в конце каждого сообщения не является решением).


person Tomasz Lewowski    schedule 26.03.2017    source источник


Ответы (1)


Чтобы что-то не прошло тест, оно должно было бы выдать ошибку утверждения какого-то потока, выполняющего тест, но, поскольку зонд является асинхронным, любое обнаружение сбоя, которое вы в него введете, произойдет в другом потоке, поэтому должны быть место, где вы вызываете метод из теста (так же, как expectNoMsg()).

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

Один из возможных способов сделать это — использовать функцию более высокого порядка:

def failOnUnexpectedMessage[T](test: ActorRef => T): T = {
  val probe = TestProbe()
  val result = test(probe.ref)
  probe.expectNoMsg()
  result
}

Затем вы можете использовать это в своих тестах (стиль спецификации слова Scalatest здесь):

"My actor" should {
  "something something" in failOnUnexpectedMessage { ref => 
    val actor = ...construct and pass it ref as b...
    ...rest of the test...
  }
}
person johanandren    schedule 03.04.2017
comment
Спасибо за объяснение - хотя я сделал что-то немного другое (expectNoMsg(0 seconds) для всех датчиков при разборке приспособления), он определенно был вдохновлен этим ответом. - person Tomasz Lewowski; 10.04.2017