Search code examples
androidmvvmmockitoviewmodeljunit4

kotlin.UninitializedPropertyAccessException: lateinit property mRepository has not been initialized


I have a method in my SearchViewModel and I want to test this method by Mockito and JUnit4.(searchCity()) but this error is shown after running the test:

kotlin.UninitializedPropertyAccessException: lateinit property mRepository has not been initialized

SearchViewModel class :

class SearchViewModel @Inject constructor() : BaseViewModel() {

    @Inject
    lateinit var mRepository: DataRepository
    @Inject
    lateinit var sharedPfs: SharedPrefs

    private var disposable: Disposable? = null
    val search = MutableLiveData<ResponseSearch>()
    val searchOWM = MutableLiveData<ResponseOWMCity>()
    val searchCityName = MutableLiveData<String>()
    val serachClick = SingleLiveEvent<Boolean>()
    val progressBar = SingleLiveEvent<Boolean>()
    val searchOWMvisibility = SingleLiveEvent<Boolean>()
    val cityOWMclick = SingleLiveEvent<ResponseOWMCity>()

    override fun getSharedPrefs(): SharedPrefs? {
        return sharedPfs
    }

    fun stop() {
        disposable?.let { if (!it.isDisposed) it.dispose() }
    }

    fun fabSearchClick(){
        serachClick.call()
    }

    fun searchCity() {
        val cityName = searchCityName.value
        if (!Strings.isEmptyOrWhitespace(cityName)) {
            progressBar.postValue(true)
            disposable = mRepository.doSearchProcess(cityName)
                ?.subscribe({
                    search.postValue(it)
                    progressBar.postValue(false)
                }, {
                    showToast(it!!.message!!)
                    progressBar.postValue(false)
                })
        } else{
            showToast("لطفا شهر دلخواه خود را وارد کنید.")
        }
    }


    fun searchCityOWM() {
        val cityName = searchCityName.value
        disposable = mRepository.doSearchProcessOWM(cityName)
            ?.subscribe({
                if (it != null){
                    searchOWM.postValue(it)
                    searchOWMvisibility.postValue(true)
                } else{
                    searchOWMvisibility.postValue(false)
                }

            }, {
                searchOWMvisibility.postValue(false)
            })

    }

    fun clickCityOWM(city: ResponseOWMCity){
        cityOWMclick.postValue(city)
    }
}

DataRepository class :

class DataRepository @Inject
    constructor(private val endPointAPI: EndPointAPI, private val localRoomDatabse: LocalRoomDatabse) {

    fun getAllSavedResults(): LiveData<List<City?>>? {
        return localRoomDatabse.roomDao().getAllResults()
    }

    fun doSearchProcess(city: String?): Observable<ResponseSearch>? {
        return endPointAPI.searchCities(Config.BASE_URL2 + city)
            .subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.doOnError({ throwable -> Log.i("1397", "remote: " + throwable.message) })
    }
}

SearchViewModelTest :

class SearchViewModelTest {

    @get:Rule
    val mockitoRule: MockitoRule = MockitoJUnit.rule()

    @get:Rule
    val taskExecutorRule = InstantTaskExecutorRule()

    @Rule
    @JvmField
    var testSchedulerRule = RxImmediateSchedulerRule()

    @Mock
    lateinit var observer: Observer<ResponseSearch>

    @Mock
    lateinit var mRepository: DataRepository

    lateinit var searchViewModel: SearchViewModel


    @Before
    @Throws(Exception::class)
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        searchViewModel = SearchViewModel()
    }


    @Test
    fun doSearchResultSuccessWithData() {

        // GIVEN
        val res = RESULT()
        res.name = "shiraz"
        val list = ArrayList<RESULT>()
        list.add(res)
        val search = ResponseSearch(list)
        val observable = Observable.just(search)


        // WHEN
        searchViewModel.searchCityName.value = "shiraz"
        searchViewModel.search.observeForever(observer)
        whenever(mRepository?.doSearchProcess("shiraz")).thenReturn(observable)
        searchViewModel.searchCity()
        // THEN
        assertNotNull(searchViewModel.search.value)
        assertThat(searchViewModel.search.value?.results?.size, CoreMatchers.`is`(1))

    }
}

can anyone help me?


Solution

  • While using Dagger and field injection, you should actually inject them with component or factory when it comes to ViewModels. While testing you can inject that mock you created here

    @Mock lateinit var mRepository: DataRepository

    using auto-generated code by Dagger

    @Before
    @Throws(Exception::class)
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        searchViewModel = SearchViewModel()
        SearchViewModel_MembersInjector.injectMRepository(searchViewModel, mRepository)
    }