Scala и Akka — Тестирование акторов как системы с помощью Akka Testkit

В моем приложении Scala у меня есть Актер A и Актер B. Я хочу разработать тестовый пример в ScalaTest, который позволил бы мне отправить сообщение Актеру A и посмотреть, какое сообщение он отправляет Актеру B, чтобы убедиться, что A правильно обрабатывает свои данные и отправляет правильное сообщение B. Как бы это проверить? Мне потребовалось много времени, чтобы приготовить это самостоятельно... но, похоже, в основном это работает.

class A extends Actor { ... }

class B extends Actor { ... }

class C(p: TestProbe) extends B {
  override def receive = {
    LoggingReceive {
      case x =>
        println(x.toString)
        p.ref ! x
    }
  }
}

case class MsgToB(...)

// Spec class which extends TestKit
"A" should {
  "send the right message to B" {
    val p = TestProbe()
    val a = TestActorRef[A]
    val c = TestActorRef(Props(new C(p)))

    // Assume A has a reference to C. Not shown here.
    a ! msg
    // Assert messages
    p.expectMsgType[MsgToB]
  }
}

Это лучший способ сделать это? Есть ли лучшая практика?


person Rig    schedule 14.04.2016    source источник


Ответы (1)


Мне кажется, что вы хотите проверить поведение актера А изолированно. Чтобы сделать это, вы должны иметь возможность контролировать, как актор A получает ссылку на актор B. Например, вы можете предоставить ссылку в конструкторе актора:

import akka.actor.{Actor, ActorRef, Props}

class A(refToB: ActorRef) extends Actor { ... }

object A {
  def props(refToB: ActorRef): Props = Props(new A(refToB))
}

Существуют альтернативные способы передачи ссылки на актор B актору A, но использование конструктора, возможно, является самым простым выбором. В приведенном выше примере мы также предоставляем метод для создания правильного Props для актера.

Теперь, когда вы можете управлять ссылкой на актор B, вы можете заменить ссылку на актор тестовым зондом в тестах.

import akka.testkit.TestProbe

// Initialise a test probe
val probe = TestProbe()

// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))

// Send a message to actor A
a ! someMessage

// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]

Обратите внимание, что я создал актера, используя систему акторов из TestKit, а не файл TestActorRef. Это означает, что обработка сообщений субъекта будет асинхронной, а не синхронной. Лично я считаю, что асинхронный стиль тестирования лучше подходит, потому что он лучше представляет, как актор запускается в производственной системе. Асинхронное тестирование также рекомендуется в официальной документации.

person Jaakko Pallari    schedule 08.08.2016
comment
Мне это нравится. Я выбрал оригинальную реализацию, потому что мне нужно было что-то сделать, но это звучит интересно. Цель состоит в том, чтобы протестировать всю систему акторов от нашего актера входа, который обрабатывает веб-запросы, до всей цепочки (фиктивных) сервисных вызовов, которые мы делаем, и проверить выходные данные, а также веб-ответ. Одной из проблем было получить асинхронное поведение, чтобы утверждения не нужно было упорядочивать. Если это работает, это решает это. - person Rig; 15.08.2016