[英]Unit Testing failures from Futures in Scala
我正在嘗試在我正在編寫的腳本中測試錯誤處理。 如果異步函數 fetchBar 失敗,我會匹配失敗案例,然后返回一個包含失敗結果的成功未來。
val fetchedBar = Try(fooClient.fetchBar(params))
fetchedBar match {
case Success(bar) => foobar(bar)
case Failure(e) => Future.successful(FooResult(success = false))
}
但是,當我對這個流程進行單元測試時,我在測試失敗案例時遇到了麻煩。 我已經存根 fetchBar 返回一個失敗的未來,如下所示。
val fetchedBar = Try(Future.failed(new Exception()))
但我注意到 fetchedBar 返回的是 Success 而不是 Failure。 為什么會這樣,我如何存根 fetchBar 函數來創建失敗的 Try?
我認為你有點混淆概念 - 但這不是 100% 你的錯。
問題是,Scala 中的Future
是一個有點非正交的概念——也就是說,它不僅代表了延遲執行的概念,還代表了一個失敗的概念。
因此,在大多數情況下,將 Future 包裝到 Try 中沒有多大意義,反之亦然 - 除非人們想明確地將失敗的概念與異步的概念分開。
換句話說,以下組合有點奇怪,但仍然有用:
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(...)
) Future.failed(...)
。 一方面 - 這對於 akka-streams 尤其有用,它傾向於將失敗的期貨視為對流來說是“致命的”。在您的情況下,您想要做的是斷言未來的結果。 要做到這一點,實際上您至少有兩個選擇。
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) => ???; }
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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.