簡體   English   中英

對使用Kotlin協程的改造電話進行單元測試

[英]Unit testing a retrofit call that uses kotlin coroutines

我正在使用Kotlin協程Kotlin改造協程在我當前正在研究的項目中進行網絡請求。 但是我無法弄清楚如何通過邏輯單元測試。

這是我的代碼:

class WorklistInteractor @Inject
    constructor(private val worklistRepository: WorklistRepository,
        private val preferenceManager: PreferenceManager)
: NetworkInteractor, WorklistDialogContract.Interactor {

    private var job = Job()

    override fun getWorklist(listener: OnWorklistResultListener) {
        job = launch(UI) {
            val result = async {
                worklistRepository.getWorklist(
                    ip = preferenceManager.worklistIp,
                    port = preferenceManager.worklistPort).awaitResult()
            }.await()

            when (result) {
            //Successful HTTP result
                is Result.Ok -> listener.onWorklistResult(result.value)
            // Any HTTP error
                is Result.Error -> {
                    Timber.e(result.exception, "HTTP error with code %s}", result.exception.code())
                    when(result.exception.code()) {
                        401 -> listener.onInvalidCredentialsFailure()
                        500 -> listener.internalServerError()
                        503 -> listener.noServerResponseFailure()
                        else -> listener.onError(result.exception.cause.toString())
                    }
                }
            // Exception while request invocation
                is Result.Exception -> {
                    Timber.e(result.exception.cause, "Exception with cause %s", result.exception.cause.toString())
                    when(result.exception) {
                        is ConnectException -> listener.connectionRefused()
                        is SocketTimeoutException -> listener.failedToConnectToHost()
                        else -> listener.onError(result.exception.cause.toString())
                    }
                }
            }
        }
    }

    override fun cancel() {
        job.cancel()
    }
}

這是我的單元測試之一:

@Test
fun `when worklistquery returns result, pass result back through listeners onWorklistResult`()
        = runBlocking {

    whenever(mWorklistRepositoryMock.getWorklist(anyString(), anyInt(), anyString()))
            .thenReturn(Calls.response(expectedWorklistResult))

    mInteractor.getWorklist(mOnWorklistResultListenerMock)

    verify(mOnWorklistResultListenerMock).onWorklistResult(expectedWorklistResult)
    verifyNoMoreInteractions(mOnWorklistResultListenerMock)
}

運行時,我不斷收到以下消息:

希望但不被調用:onWorklistResultListener.onWorklistResult(); ->在com.example.dialogs.worklistdialog.WorklistInteractorTest $中,當worklistquery返回結果時,將結果通過偵聽器傳遞回OnWorklistResult()$ 1.doResume(WorklistInteractorTest.kt:58)

實際上,與該模擬游戲的互動為零。

您找到了解決方案,但也許對其他人(尤其是初學者)而言,解釋為什么首先出現錯誤以及runBlocking為何runBlocking幫助可能會有所幫助。 問題是,在運行單元測試時,期望這些測試是同步的,也就是說,如果一段時間后在某個單獨的線程上執行任何代碼,測試運行程序將永遠不會知道這一點,因為對於測試運行程序當測試運行程序線程上的方法調用完成時,測試完成。

因此,不可能測試不在主線程上運行的代碼。 實際上,嘗試這樣做甚至是不好的做法。 由於無法保證在另一個線程上運行的代碼何時完成(如果有的話),因此我們不知道主線程當時處於什么狀態(這種情況下主線程甚至可能不再存在) (帶有單元測試運行程序)。

即使可以以某種方式測試在其他線程中執行的代碼,每次測試運行也不可避免地會有所不同(由於上述段落),並且測試可能會在每次運行中產生不同的結果。 這直接與可靠的測試思想背道而馳,並且每次運行都會產生相同的結果。

因此,在測試時,所有測試的代碼都需要在主線程上運行,並且應確保切勿嘗試在測試中調用任何異步代碼。

毫無疑問, runBlocking協程在其從其啟動的線程上以阻塞的方式運行了其中的代碼(與launch相對,這將導致代碼異步運行)。

所有這些都有一個警告,協程不是線程,但是如果您在上述文本中將thread一詞替換為asynchronous coroutine ,則該文本不會失去任何含義。 我所說的內容既適用於使用傳統線程的情況,也適用於使用協程的情況。

必須相當大地改變實施。 事實證明,如果不從Android活動/片段中使用常規函數中的launch協程生成器,則不是那么簡單。

我沒有使用常規函數,而是將getWorklist()函數更改為掛起函數,並與withContextwithContext器一起使用。 這是新的實現:

override suspend fun getWorklist(listener: OnWorklistResultListener) {
        withContext(CommonPool) {
            Timber.i("Loading worklist")
            val result = worklistRepository.getWorklist(
                    ip = preferenceManager.worklistIp,
                    port = preferenceManager.worklistPort,
                    aeTitle = preferenceManager.worklistAeTitle)
                    .awaitResult()
            when (result) {
            //Successful HTTP result
           ... left out for brevity (it's the same as before) ...

現在所有測試都通過了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM