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)
}
}
@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.