【问题标题】:How to test my viewModel that is Koin injected?如何测试我注入 Koin 的 viewModel?
【发布时间】:2020-12-07 17:19:07
【问题描述】:

我有一个 ViewModel。它在我的数据仓库中调用一个函数并返回一个狗对象的列表。

class MainViewModel() : ViewModel() {
    private val dataRepo: DataRepo by inject(DataRepo::class.java) //dataRepo
    private var limit = 10
    private val _dogListLiveData = MutableLiveData<List<Dog>>()
    private var dogList = mutableListOf<Dog>()

    val dogListLiveData: MutableLiveData<List<Dog>>
        get() = _dogListLiveData

    fun searchByBreed(queryText: String) {
        dataRepo.searchByBreed(
            queryText,
            object : DataSource.OnResponseCallback<List<Dog>, String> {
                override fun onSuccess(obj: List<Dog>?) {
                    dogList = mutableListOf()
                    if(!obj.isNullOrEmpty()){
                    dogList.addAll(obj)
                    dogListLiveData.value = dogList.take(limit)
                    }

                }

                override fun onError(error: String) {
                    Log.i("Calling Network Service", error)
                }
            })

    }

    fun loadPaginateBreed() : Boolean{
        return if ((limit+10) < dogList.size) {
            limit += 10
            Log.i("Pagination new Limit", limit.toString())
            dogListLiveData.value = dogList.take(limit)
            false
        }else{
            limit += dogList.size%limit
            dogListLiveData.value = dogList.take(limit)
            true
        }
    }
}

我需要为它编写一个简单的单元测试。我已经写了这个并尝试了许多其他迭代。但似乎没有任何效果。

package com.example.koinapplication.ui.main

import androidx.lifecycle.Observer
import com.example.koinapplication.custom.adpaters.GranularErrorCallAdapterFactory
import com.example.koinapplication.models.Dog
import com.example.koinapplication.models.Height
import com.example.koinapplication.models.Weight
import com.example.koinapplication.repo.*
import org.junit.After
import org.junit.Before
import org.junit.Test

import org.junit.Assert.*
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.dsl.module
import org.koin.java.KoinJavaComponent.inject
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import java.util.*

class MainViewModelTest {


    private val mainViewModel: MainViewModel by inject(MainViewModel::class.java)

    lateinit var obserserData : Observer<List<Dog>>

    private val networkModule = module {
        factory { AuthInterceptor() }
        factory { provideOkHttpClient(get()) }
        factory { GranularErrorCallAdapterFactory<Any>() }
        single { providesNetworkClient(get(), get()) }
        single { DataRepo(get()) }
        single { NetworkRepo(get()) }
    }


    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        startKoin {
            modules(arrayListOf(networkModule))
        }
    }

    @After
    fun tearDown() {
        stopKoin()
    }

    @Test
    fun searchByBreed() {
        mainViewModel.dogListLiveData.observeForever { obserserData }
        mainViewModel.searchByBreed("dal")
        Mockito.verify(obserserData).onChanged(mainViewModel.dogListLiveData.value)
    }
}

请帮我写一个简单的测试来测试我的 viewModel 中的数据。非常感谢您的帮助。

【问题讨论】:

    标签: java android kotlin android-viewmodel koin


    【解决方案1】:

    最好将所有依赖注入 (DI) 框架排除在您的 ViewModel 之外。这使您的 ViewModel 独立并简化了您的单元测试。

    视图模型

    因此,您可以通过构造函数传递它们,而不是在 ViewModel 中注入依赖项:

    class MainViewModel(
        private val dataRepo: dataRepo
    ) : ViewModel() {
        // ...
    }
    

    Koin 模块

    在您的 Koin 模块中,您可以定义依赖项并提供 ViewModel 的实例:

    module {
      single { DataRepo(get()) }
      factory { MainViewModel(dataRepo = get())}
    }
    

    然后,您可以像往常一样在您的 Activity 或 Fragment 中注入您的 ViewModel。

    单元测试

    在您的MainViewModelTest 中,您不需要任何 Koin 代码:

    class MainViewModelTest {
        private val dataRepo: DataRepo = mockk() // I used Mockk for mocking, but you can use any other mocking framework
    
        private val mainViewModel = MainViewModel(dataRepo) // your class under test
    
        @Test
        fun yourTest() {
            // prepare
            every { dataRepo.searchByBreed(...)} returns ...
    
            mainViewModel.searchByBreed(queryText = "...")
    
            // do assertions
        }
    }
    

    有了这个,大大简化了编写单元测试。您可以稍后将 Koin 与任何其他 DI 框架交换,而无需接触您的 ViewModel 和测试。

    希望对你有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多