Как мне издеваться над методом onComplete будущего?

У меня есть актер Akka, который работает с сообщением, содержащим будущее. Вот его упрощенная версия:

case class MyMessage(s: Future[String])

class MyWorker extends Actor {
  override def receive: Receive = {
    case MyMessage(future) =>
      future onComplete {
        case Success(s) => sender ! s
        case Failure(e) => throw e
      }
  }
}

Я использую TestActorRef для тестирования в спецификации2, но когда я пишу такую ​​спецификацию:

class MyWorkerSpec extends Specification with Mockito {

  val worker = TestActorRef(new MyWorker)

  "MyMessage" should {

    "return the string from a successful result" in {
      val message = MyMessage(Future("test"))
      val result = worker ? message
      result.value.get must_== Success("test")
    }

  }
}

...тогда с NoSuchElementException: None.get происходит сбой, и система Akka жалуется на мертвые буквы.

Подумав, что это, вероятно, потому, что он не ждет завершения будущего, я решил попробовать смоделировать будущее и заглушить метод onSuccess. Однако я не уверен, как это сделать, потому что аргумент func, очевидно, является Any.

class MyWorkerSpec extends Specification with Mockito {

  val worker = TestActorRef(new MyWorker)

  "MyMessage" should {

    "return the string from a successful result" in {
      val mockFuture = mock[Future[String]]
      mockFuture.onComplete(any[Try[String] => String]) answers {
        func => {
          func(Success("test"))
        }
      }
      worker ! MyMessage(mockFuture)
    }
  }
}

Как можно насмехаться над таким будущим? Или есть лучший способ сделать это?


person Joel Young    schedule 04.06.2014    source источник
comment
Как вы инициализируете этот TestActorRef под капотом? Это на самом деле проходит через actorOf(...)?   -  person wheaties    schedule 04.06.2014


Ответы (1)


Я не думаю, что здесь требуется издевательство.

1- Как насчет создания вашего Future вот так: MyMessage(Future.successful("test")), таким образом, он будет завершен, когда вы его создадите.

2- Вы должны подождать, пока ваш актер ответит, прежде чем звонить value на result:

val result = worker ? message
Await.result(result, duration) must_== Success("test")

См.: http://www.scala-lang.org/api/current/index.html#scala.concurrent.Await%24

3- Отправка экземпляра Future актеру кажется мне ужасной идеей.

person vptheron    schedule 04.06.2014
comment
Большой +1 по пункту 3. Future нельзя отправлять между виртуальными машинами, поэтому их отправка между субъектами разрушает масштабируемость приложения. - person wingedsubmariner; 04.06.2014
comment
Я новичок в scala и функциональном программировании в целом, поэтому я весь в слухах о том, почему вы думаете, что посылать будущее актеру - плохая идея. Будущее создается более ранним действующим лицом, и я подумал, что было бы хорошо отложить ожидание результата до самого последнего возможного момента. Проблема, конечно, в том, что это добавляет эту сложность. - person Joel Young; 04.06.2014
comment
Только что увидел комментарий wingedsubmariner - очень хороший момент. Я перестану отправлять фьючерсы. - person Joel Young; 04.06.2014
comment
Вам следует больше узнать об API Future/Promise. Вызов onComplete от актера не дает вам ровно ничего по сравнению с простым вызовом onComplete после создания Future. onComplete неблокирует, вы просто регистрируете обработчик, который будет выполняться, когда Future завершится. Отличный ресурс для получения дополнительной информации: danielwestheide.com/blog/2013/01/09/ - person vptheron; 04.06.2014
comment
Я понимаю, что вы имеете в виду о onComplete. Раньше я ошибочно принимал его за блокирующий API. - person Joel Young; 05.06.2014
comment
Всем спасибо за помощь, но изначальная проблема с получением мертвых букв при использовании onComplete в акторе осталась. Я создал новый вопрос, чтобы получить это: stackoverflow.com/questions/24049457/ - person Joel Young; 05.06.2014