2017-03-01 60 views
1

我的一些代碼是異步的,我想測試這個代碼的執行導致了正確的狀態。我沒有提及可以映射的Future或JS Promise的參考 - 所討論的異步代碼存在於我正在使用的JS庫中,它只是調用setTimeout(setSomeState, 0),這就是爲什麼我唯一的追求是測試該狀態在短暫延遲(10毫秒)後異步。如何編寫異步Scala.js測試(例如使用ScalaTest)?

這是我最好的嘗試:

import org.scalatest.{Assertion, AsyncFunSpec, Matchers}  
import scala.concurrent.Promise 
import scala.scalajs.js 
import scala.scalajs.concurrent.JSExecutionContext 

class FooSpec extends AsyncFunSpec with Matchers { 

    implicit override def executionContext = JSExecutionContext.queue 

    it("async works") { 
    val promise = Promise[Assertion]() 

    js.timers.setTimeout(10) { 
     promise.success { 
     println("FOO") 
     assert(true) 
     } 
    } 

    promise.future 
    } 
} 

這工作時斷言成功 - 與assert(true)。但是,當斷言失敗時(例如,如果用assert(false)替換它),測試套件將凍結。 sbt只是停止打印任何東西,並無限期地掛起,測試套件永遠不會完成。如果發生此類故障,則FooSpec:行會打印,但不會顯示測試的名稱("async works")和"FOO"字符串。

如果我註釋掉executionContext這一行,我會得到「隊列爲空,而未來未完成,這意味着您可能使用了錯誤的ExecutionContext來完成您的任務,請仔細檢查您的未來。錯誤在下面的一個鏈接中詳細解釋。

我認爲這些鏈接是有關這個問題:

https://github.com/scalatest/scalatest/issues/910

https://github.com/scalatest/scalatest/issues/1039

但我無法找出一個解決方案,將工作。

我應該以不同的方式構建Future[Assertion],也許?

我沒有被綁定到ScalaTest,但通過上面的鏈接之一的評論來看,似乎uTest有一個類似的問題,除了它傾向於忽略測試而不是拖延測試套件。

我只是想在短暫的延遲後作出斷言,似乎應該是絕對有可能的。任何有關如何實現這一目標的建議都將非常感激。

回答

1

正如在this scala.js gitter thread中向我解釋的,我錯誤地使用了Promise.success。該方法需要一個值來完成承諾,但assert(false)引發異常,它不會返回類型爲Assertion的值。

由於在我的代碼中assert(false)在調用Promise.success之前被評估,所以在承諾有機會完成之前拋出異常。但是,該異常在setTimeout的同步回調中​​引發,因此它對ScalaTest不可見。 ScalaTest然後等待promise.future永不完成(因爲潛在的承諾永遠不會完成)。

基本上,我的代碼是相同的:

val promise = Promise[Assertion]() 
js.timers.setTimeout(10) { 
    println("FOO") 
    val successValue = assert(false) // exception thrown here 
    promise.success(successValue) // this line does not get executed 
} 
promise.future 

相反,我應該用Promise.complete一個希望將TryTry.apply接受通過名稱模式的參數,這意味着它將僅在調用Try()後才被評估。

所以工作代碼如下所示:

it("async works") { 
    val promise = Promise[Assertion]() 
    js.timers.setTimeout(10) { 
    promise.complete(Try({ 
     println("FOO") 
     assert(true) 
    }) 
    }) 
    promise.future 
} 
0

真正答案這裏是:你應該嘗試的「異步」的一部分你的單元測試設置的

所有處理等待;睡覺;等等增加了一個複雜度,你不需要想要在你的單元測試中有。

由於您沒有顯示您正在使用的生產代碼,因此我只能提出一些建議以在一般水平上處理此主題。

示例:當您在Java的ExecutorService上構建線程時,您可以使用same-thread執行程序服務;你的單元測試正在使用單線程;許多事情變得更容易。長話短說:考慮一下在你的解決方案中給你「異步」的那個「概念」。如果有辦法避免「真正異步」的部分;但是當然沒有(!)對您的生產代碼進行僅測試更改。

+0

對不起,我不明白我怎麼可以把這個給我的處境。我在JS庫裏面調用了一個'baz'方法,裏面有這個JS代碼:'setTimeout(setSomeState,0)'。我需要聲明'setSomeState'已經對我在測試範圍內的變量進行了必要的修改。在我上面的例子中,我把它抽象爲'assert(true)'。但是這個斷言顯然需要在* setSomeState運行之後發生,因此斷言必須是異步的。 – Nikita

+0

嗯,這更像是一個通用的想法......當它不適用時,我可以刪除答案。 – GhostCat

相關問題