Search code examples
androidunit-testingkotlinmvvmkoin

How to Unit Test MVVM with Koin?


How to Unit Test MVVM with Koin ?

i've try to testing : link

But, i don't know why i get error("No Data in ViewModel") in ViewModelTest fun getLookUpLeagueList()

Repository

class LookUpLeagueRepository {

    fun getLookUpLeague(idLeague: String): MutableLiveData<LookUpLeague> {
        val lookUpLeague = MutableLiveData<LookUpLeague>()
        APIService().getLookUpLeague(idLeague).enqueue(object : Callback<LookUpLeague> {
            override fun onFailure(call: Call<LookUpLeague>, t: Throwable) {
                d("TAG", "lookUpLeagueOnFailure ${t.localizedMessage}")
            }

            override fun onResponse(call: Call<LookUpLeague>, response: Response<LookUpLeague>) {
                lookUpLeague.value = response.body()
            }
        })
        return lookUpLeague
    }
}

ViewModel

class LookUpLeagueViewModel(private val lookUpLeagueRepository: LookUpLeagueRepository) :
    ViewModel() {

    var lookUpLeagueList = MutableLiveData<LookUpLeague>()

    fun getLookUpLeagueList(idLeague: String) {
        lookUpLeagueList = lookUpLeagueRepository.getLookUpLeague(idLeague)
    }
}

Module

val lookUpLeagueModule = module {
    single { LookUpLeagueRepository() }
    viewModel { LookUpLeagueViewModel(get()) }
}

ViewModel Test

class LookUpLeagueViewModelTest : KoinTest {

    val lookUpLeagueViewModel: LookUpLeagueViewModel by inject()

    val idLeague = "4328"

    @get:Rule
    val rule = InstantTaskExecutorRule()

    @Mock
    lateinit var observerData: Observer<LookUpLeague>

    @Before
    fun before() {
        MockitoAnnotations.initMocks(this)
        startKoin {
            modules(lookUpLeagueModule)
        }
    }

    @After
    fun after() {
        stopKoin()
    }

    @Test
    fun getLookUpLeagueList() {
        lookUpLeagueViewModel.lookUpLeagueList.observeForever(observerData)

        lookUpLeagueViewModel.getLookUpLeagueList(idLeague)

        val value = lookUpLeagueViewModel.lookUpLeagueList.value ?: error("No Data in ViewModel")

        Mockito.verify(observerData).onChanged(value)
    }
}

Solution

  • @Test
    fun getLookUpLeagueList() {
        lookUpLeagueViewModel.lookUpLeagueList.observeForever(observerData)
        ...
    }
    

    At this time lookUpLeagueList is an instance of MutableLiveData. Say this is MutableLiveData #1.

    lookUpLeagueViewModel.getLookUpLeagueList(idLeague)
    

    Executing the line above would call LookUpLeagueViewModel.getLookUpLeagueList function. Let's take a look inside it.

    lookUpLeagueList = lookUpLeagueRepository.getLookUpLeague(idLeague)
    

    A totally new MutableLiveData is created inside LookUpLeagueRepository. That is not the same one as the one observerData is observing. At this time lookUpLeagueViewModel.lookUpLeagueList refers to the new one, MutableLiveData #2 because you re-assigned it to var lookUpLeagueList.

    val value = lookUpLeagueViewModel.lookUpLeagueList.value ?: error("No Data in ViewModel")
    

    Therefore, you're actually querying against MutableLiveData #2 which is new, not observed, and empty. That's why value is null. Instead of declaring as var, you should make it val. Don't re-assign the variable, setValue or postValue to propagate the change.