使用 Mockk 错误单元测试多个协程和单例模拟

问题描述

我有这个 Homeviewmodel 类,我想对其进行单元测试。但是我不断收到错误消息,说我的方法没有被调用。这是我的 Homeviewmodel

class Homeviewmodel(private val repository: Repository): viewmodel() {
    private var _tvTrending = mutablelivedata<MutableList<TvTrending>>(mutablelistof())
    private var _mvTrending = mutablelivedata<MutableList<MvTrending>>(mutablelistof())
    private var _mvPopular = mutablelivedata<MutableList<MvPopular>>(mutablelistof())
    private var _tvPopular = mutablelivedata<MutableList<TvPopular>>(mutablelistof())
    
    fun loadData(){
        viewmodelScope.launch {
            launch {
                _tvTrending.value?.clear()
                _tvTrending.value?.addAll(repository.getTvTrending()) }
            launch {
                _tvPopular.value?.clear()
                _tvPopular.value?.addAll(repository.getTvPopular()) }
            launch {
                _mvTrending.value?.clear()
                _mvTrending.value?.addAll(repository.getMvTrending()) }
            launch {
                _mvPopular.value?.clear()
                _mvPopular.value?.addAll(repository.getMvPopular()) }
        }
    }
}

我的存储库是单例的,看起来像这样,

class Repository private constructor(private val context: Context){
    init {
        println("Repository is Being Called")
    }

suspend fun getTvTrending(): List<TvTrending> {
    val result = mutablelistof<TvTrending>()
    Coroutinescope(IO).launch {
        val local = async { LocalDatabase.getInstance(context).localRepo.getTvTrending()}
        if(local.await().isEmpty()){
            println("Get TV Trending Called : Online")
            val remote = withContext(dispatchers.Default) { RemoteRepo.instance.getTvTrending() }
            result.addAll(remote)
            LocalDatabase.getInstance(context).localRepo.insertTvTrending(remote)
        }else{
            println("Get TV Trending Called : Local")
            result.addAll(local.await())
        }
    }
    return result
}

suspend fun getTvPopular(): List<TvPopular> {
    val result = mutablelistof<TvPopular>()
    Coroutinescope(IO).launch {
        val local = async { LocalDatabase.getInstance(context).localRepo.getTvPopular()}
        if(local.await().isEmpty()){
            println("Get TV Popular Called : Online")
            val remote = withContext(dispatchers.Default) { RemoteRepo.instance.getTvPopular() }
            result.addAll(remote)
            LocalDatabase.getInstance(context).localRepo.insertTvPopular(remote)
        }else{
            println("Get TV Popular Called : Local")
            result.addAll(local.await())
        }
    }
    return result
}

suspend fun getMvTrending(): List<MvTrending> {
    val result = mutablelistof<MvTrending>()
    Coroutinescope(IO).launch {
        val local = async { LocalDatabase.getInstance(context).localRepo.getMvTrending()}
        if(local.await().isEmpty()){
            println("Get MV Trending Called : Online")
            val remote = withContext(dispatchers.Default) { RemoteRepo.instance.getMvTrending() }
            result.addAll(remote)
            LocalDatabase.getInstance(context).localRepo.insertMvTrending(remote)
        }else{
            println("Get MV Trending Called : Local")
            result.addAll(local.await())
        }
    }
    return result
}

suspend fun getMvPopular(): List<MvPopular> {
    val result = mutablelistof<MvPopular>()
    Coroutinescope(IO).launch {
        val local = async { LocalDatabase.getInstance(context).localRepo.getMvPopular()}
        if(local.await().isEmpty()){
            println("Get MV Popular Called : Online")
            val remote = withContext(dispatchers.Default) { RemoteRepo.instance.getMvPopular() }
            result.addAll(remote)
            LocalDatabase.getInstance(context).localRepo.insertMvPopular(remote)
        }else{
            println("Get MV Popular Called : Local")
            result.addAll(local.await())
        }
    }
    return result
}
private fun println(s: String){
    Log.d(TAG,s)
}

companion object: SingletonHolder<Repository,Context>(::Repository) {
    private const val TAG = "Repository"
}

}

我正在使用 mockk 并尝试创建单元测试,但它引发了我的错误

@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class HomeviewmodelTest {
    private lateinit var homeviewmodel: Homeviewmodel
    private val mainThreadSurrogate = newSinglethreadcontext("UI thread")
    private lateinit var context: Context


@Before
fun setUp() {
    dispatchers.setMain(mainThreadSurrogate)
    context = mockk<Context>(relaxed = true)
    mockkObject(Repository)
    mockkObject(Repository.Companion)
    homeviewmodel = Homeviewmodel(Repository.getInstance(context))
}

@After
fun tearDown() {
    dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
    mainThreadSurrogate.close()
}

@Test
fun loadData_successfullyRequest() {
    coEvery { Repository.getInstance(context).getTvTrending() } returns emptyList()
    coEvery { Repository.getInstance(context).getTvPopular() } returns emptyList()
    coEvery { Repository.getInstance(context).getMvTrending() } returns emptyList()
    coEvery { Repository.getInstance(context).getMvPopular() } returns emptyList()

    runBlocking {
        launch(dispatchers.Main) {
            homeviewmodel.loadData()
        }
    }
    coVerify { Repository.getInstance(context).getTvTrending() }
    coVerify { Repository.getInstance(context).getTvPopular() }
    coVerify { Repository.getInstance(context).getMvTrending() }
    coVerify { Repository.getInstance(context).getMvPopular() }
}
}

有没有人有解决这个问题的想法?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)