【问题标题】:Android Studio Coroutine Tests Passing individually, failing when run togetherAndroid Studio协程测试单独通过,一起运行失败
【发布时间】:2020-06-07 09:08:50
【问题描述】:

我知道这个问题已经被问了很多不同的方法,有很多不同的答案,但我看不出任何帮助我的情况。我正在尝试使用协程测试演示者。为了验证行为,我实现了com.nhaarman.mockitokotlin2.mock。所有测试单独通过,但一起运行时它们随机失败(2 次通过、1 次通过、3 次通过等)

我在协程方面没有太多经验,所以我希望有更多经验的人可以指导我。下面是我的测试课。如果需要,我可以添加更多信息

package com.project.ui.search.results

import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.whenever
import ie.distilledsch.dschapi.models.search.SavedSearchCreateResponse
import io.reactivex.schedulers.TestScheduler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import retrofit2.HttpException

@ExperimentalCoroutinesApi
class SPSearchResultsPresenterSavedSearchesTest {

    @get:Rule val testCoroutineRule = TestCoroutineRule()
    private lateinit var interactor: SPSearchResultsInteractor
    @Mock private lateinit var view: SPSearchResultsView
    @Mock private lateinit var context: Context
    @Mock private lateinit var interactorBtwAdListAndAdDetails: InteractorBetweenListOfAdsAndAdDetails
    @Mock private lateinit var daftLoginManager: DaftLoginManager
    private lateinit var searchForm: SearchForm
    private lateinit var searchManager: SearchManager
    private lateinit var testScheduler: TestScheduler
    lateinit var presenter: SPSearchResultsPresenter

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        interactor = mock()
        testScheduler = TestScheduler()
        searchForm = SearchForm()
        searchManager = SearchManager(searchForm)
        val presenterToTest = SPSearchResultsPresenterImpl(testScheduler, testScheduler,
                testScheduler, Dispatchers.Main, Dispatchers.IO, interactorBtwAdListAndAdDetails, daftLoginManager, context, view)
        presenterToTest.interactor = interactor
        presenterToTest.searchManager = searchManager
        presenter = presenterToTest
    }

    @Test
    fun `save search dialog confirm click success`() = runBlocking {
        val savedSearchTitle = "title"
        val savedSearchID = 1234
        val responseModel = SavedSearchCreateResponse(201, "Created", savedSearchID)
        whenever(interactor.saveNewSearch(savedSearchTitle)).thenReturn(responseModel)

        presenter.onSaveSearchDialogOkClick(savedSearchTitle)
        verify(interactor).saveNewSearch(savedSearchTitle)
        verify(view).displayIconForSavedSearch()
    }

    @Test
    fun `save search dialog confirm click failure`() = runBlocking {
        val savedSearchTitle = "title"
        val exception :HttpException = mock()

        doThrow(exception).`when`(interactor).saveNewSearch(savedSearchTitle)
        presenter.onSaveSearchDialogOkClick(savedSearchTitle)
        verify(interactor).saveNewSearch(savedSearchTitle)
        verify(view, never()).displayIconForSavedSearch()
        verify(view).showFetchSavedSearchFailedToast()
    }

    @Test
    fun `delete search success logged in`() = runBlocking {
        val savedSearchID = 1234
        whenever(interactor.isUserLoggedIn()).thenReturn(true)
        searchManager.isSearchSaved = true
        searchManager.savedSearchId = savedSearchID
        presenter.onSaveMenuItemClick()
        verify(interactor).deleteSavedSearch(savedSearchID)
        verify(view).displayIconForUnsavedSearch()
    }

    @Test
    fun `delete search error logged in`() = runBlocking {
        val savedSearchID = 1234
        val exception :HttpException = mock()
        whenever(interactor.isUserLoggedIn()).thenReturn(true)
        searchManager.isSearchSaved = true
        searchManager.savedSearchId = savedSearchID
        whenever(interactor.deleteSavedSearch(savedSearchID)).thenThrow(exception)
        presenter.onSaveMenuItemClick()
        verify(interactor).deleteSavedSearch(savedSearchID)
        verify(view, never()).displayIconForUnsavedSearch()
        verify(view).showSnackBar(ArgumentMatchers.anyInt())
    }

    @Test
    fun `click on save search not logged in` () = runBlocking {
        whenever(interactor.isUserLoggedIn()).thenReturn(false)
        presenter.onSaveMenuItemClick()
        verify(view).showLoginScreen()
    }
}

【问题讨论】:

  • TestCorotuneRule 好像有问题,你能显示这个吗?

标签: android unit-testing kotlin-coroutines android-mvp


【解决方案1】:

这取决于您的 TestCoroutineRule 类中的内容,但您绝对应该做的一件事是将 TestDispatcher 注入您的演示者,以代替 Dispatchers.Main 和 Dispatchers.IO。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    相关资源
    最近更新 更多