Я думаю, что вы немного смешиваете понятия - но это не на 100% ваша вина.
Дело в том, что Future
в Scala - это немного неортогональное понятие - так оно и есть, оно представляет не только понятие отложенного выполнения, но и понятие неудачи.
Из-за этого в большинстве случаев нет смысла заключать будущее в попытку, или наоборот - если только хочет явно отделить понятие неудачи от понятия асинхронности.
Другими словами, следующие комбинации являются странными, но все же имеют свое применение:
Try[Future[_]]
- будущее уже охватывает неудачи. Однако имеет смысл, если у вас есть (плохое поведение) библиотечный метод, который обычно возвращает Future, но может выдать «синхронный» путь:
def futureReciprocal(i: Int): Float = {
val reciprocal = 1 / i // Division by zero is intentional
Future.successful(reciprocal)
}
futureReciprocal(0) // throws
Try(futureReciprocal(0)) // Failure(DivisionByZero(...))
... но это в основном Обходной путь для исправления плохо реализованной функции
Future[Try[_]]
- иногда полезно отделить «бизнес» ошибку (представленную
Future.success(Failure(...))
) от сбоя «инфраструктуры» (представлен
Future.failed(...)
). На стороне - это особенно полезно с потоками akka, которые склонны рассматривать неудачные фьючерсы как «фатальные» для потока.
В вашем случае вы хотите заявить о результат будущего. Для этого у вас есть как минимум два варианта.
- Заблокируйте до завершения будущего и проверьте результат - обычно это делается с помощью
scala.concurrent.Await
:
// writing this without the compiler, might mix up namespaces a bit
import scala.concurrent.Await
import scala.concurrent.duration.DurationInt
val future = fooClient.fetchBar(...)
val futureResult: Try[_] = Await.result(future, 1.second)
futureResult match { case Success(_) => ??? ; case Failure(exc) => ???; }
Используйте некоторую тестовую среду, которая поддерживает работу с фьючерсами, например, scalatest:
class YourTest extends FlatSpec with ScalaFutures {
"fetchBar should return failed future" in {
val future: Future[XYZ] = fooClient.fetchBar(...)
// whenReady comes from the ScalaFutures trait
whenReady(future) { result => result shouldBe XYZ } // asserting on the successful future result
whenReady(future.failed) { exc => exc shoulBe a[RuntimeException] } // asserting on an exception in the failed future
}
}