kotlin - 一起运行时,测试会失败,但是单独运行会成功,即使在每次测试之前重新模拟实例

标签 kotlin junit mockito junit4

我查看了this SO帖子,并确保我的测试没有共享相同的模拟实例,但是当一起运行时测试仍然会失败,而单独运行时测试会成功。

我怀疑可能有某种原因阻止每次测试后重新模拟我的实例,但是我对Mockito的经验不足以识别问题

这是我的考试课

package com.relic.viewmodel

import android.arch.core.executor.testing.InstantTaskExecutorRule
import android.arch.lifecycle.Observer
import com.nhaarman.mockitokotlin2.*
import com.relic.api.response.Data
import com.relic.api.response.Listing
import com.relic.data.PostRepository
import com.relic.data.UserRepository
import com.relic.data.gateway.PostGateway
import com.relic.domain.models.ListingItem
import com.relic.domain.models.UserModel
import com.relic.presentation.displayuser.DisplayUserVM
import com.relic.presentation.displayuser.ErrorData
import com.relic.presentation.displayuser.UserTab
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.setMain
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@ExperimentalCoroutinesApi
class UserVMTest {
    @get:Rule
    val rule = InstantTaskExecutorRule()

    private lateinit var postRepo : PostRepository
    private lateinit var userRepo : UserRepository
    private lateinit var postGateway : PostGateway

    private val username = "testUsername"

    init {
        val mainThreadSurrogate = newSingleThreadContext("Test thread")
        Dispatchers.setMain(mainThreadSurrogate)
    }

    @Before
    fun setup() {
        postRepo = mock()
        userRepo = mock()
        postGateway = mock()
    }

    @Test
    fun `user retrieved on init`() = runBlocking {
        val mockUser = mock<UserModel>()
        whenever(userRepo.retrieveUser(username)).doReturn(mockUser)

        val vm = DisplayUserVM(postRepo, userRepo, postGateway, username)

        val observer : Observer<UserModel> = mock()
        vm.userLiveData.observeForever(observer)

        verify(userRepo, times(1)).retrieveUser(username)
        verify(observer).onChanged(mockUser)
    }

    @Test
    fun `livedata updated when posts retrieved` () = runBlocking {
        val mockListingItems = listOf<ListingItem>(mock())
        val listing = mockListing(mockListingItems)
        whenever(postRepo.retrieveUserListing(any(), any(), any())).doReturn(listing)

        val tab = UserTab.Saved
        val vm = DisplayUserVM(postRepo, userRepo, postGateway, username)

        val observer : Observer<List<ListingItem>> = mock()
        vm.getTabPostsLiveData(tab).observeForever(observer)
        vm.requestPosts(tab, true)

        verify(postRepo, times(1)).retrieveUserListing(any(), any(), any())
        verify(observer, times(1)).onChanged(mockListingItems)
    }

    @Test
    fun `error livedata updated when no posts retrieved` () = runBlocking {
        val listing = mockListing()
        val localPostRepo = postRepo
        whenever(localPostRepo.retrieveUserListing(any(), any(), any())).doReturn(listing)

        val tab = UserTab.Saved
        val vm = DisplayUserVM(postRepo, userRepo, postGateway, username)

        val listingObserver : Observer<List<ListingItem>> = mock()
        vm.getTabPostsLiveData(tab).observeForever(listingObserver)

        val errorObserver : Observer<ErrorData> = mock()
        vm.errorLiveData.observeForever(errorObserver)

        vm.requestPosts(tab, true)

        verify(postRepo, times(1)).retrieveUserListing(any(), any(), any())
        // listing livedata shouldn't be updated, but an "error" should be posted
        verify(listingObserver, never()).onChanged(any())
        verify(errorObserver, times(1)).onChanged(ErrorData.NoMorePosts(tab))
    }

    private fun mockListing(
        listingItems : List<ListingItem> = emptyList()
    ) : Listing<ListingItem> {

        val data = Data<ListingItem>().apply {
            children = listingItems
        }

        return Listing(kind = "", data = data)
    }
}

最佳答案

好了,经过更多阅读之后,我已经更新了代码,以便使用TestCoroutineDispatcher而不是newSingleThreadContext()。我还按照此处https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/的说明添加了拆解方法

@After
fun teardown() {
    Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
    mainThreadSurrogate.cleanupTestCoroutines()
}

测试现在成功运行

关于kotlin - 一起运行时,测试会失败,但是单独运行会成功,即使在每次测试之前重新模拟实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56614154/

相关文章:

android - Unresolved reference - Activity 无法识别 android studio v4 中的合成导入

java - 在 JUnit 中运行所有测试后调用方法

java - 如何测试 FileInputStream 已经关闭?

java - 如何使用 Mockito 将模拟注入(inject)抽象父类中的 @Autowired 字段

java - 使用 Mockito 模拟枚举?

kotlin - 从多个来源收集数据的惯用方式是什么?

java - Android kotlin accountkit - 无法正常工作

android - 将 Single<Boolean> 转换为 Boolean (Kotlin)

java - JUnit 测试中的未知实体 : java. lang.Long

java - 模拟静态类