I am using unit testing when I run test I am getting following exception
ateinit property fakeAuthRepository has not been initialized
kotlin.UninitializedPropertyAccessException: lateinit property fakeAuthRepository has not been initialized
below my ViewModel test where test giving an exception
internal class SignInViewModelTest{
private val _login = MutableStateFlow<UiStateObject<SignInResponse>>(UiStateObject.EMPTY)
#Mock
lateinit var backendApi:BackendApi
lateinit var fakeAuthRepository: FakeAuthRepository
lateinit var authRepository: AuthRepository
private lateinit var viewModel: SignInViewModel
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
fakeAuthRepository = FakeAuthRepository(backendApi)
authRepository = AuthRepository(backendApi)
viewModel = SignInViewModel(authRepository)
}
var login = _login
#Test
fun `testing repository`() = runBlockingTest {
val fake = fakeAuthRepository.login("kyodgorbek#gmail.com", "12345678", "android", "123455")
val real = authRepository.login("kyodgorbek#gmail.com", "12345678", "android", "123455")
assertEquals(fake, real)
}
}
#Before is junit4 annotation.
If you are using junit5 you have to replace it with #BeforeEach.
Related
I am trying to test DataSource with Proto DataStore.
class PreferenceDataSource #Inject constructor(
private val userPreferences: DataStore<UserPreferences>
)
So, I am implementing like this:
#RunWith(RobolectricTestRunner::class)
#ExperimentalCoroutinesApi
class PreferenceDataSourceTest {
#get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
private lateinit var prefDataSource: PreferenceDataSource
#Before
fun setUp(){
Dispatchers.setMain(Dispatchers.Unconfined)
MockKAnnotations.init(this, relaxed = true)
val datastore = DataStore<UserPreferences>() // this doesn't work.
prefDataSource = PreferenceDataSource(userPreferences = datastore)
}
#Test
fun test() {
}
}
How can I test with Proto DataStore? I mean, I don't want to fake it but want to see if it really updates or deletes correctly as well.
Here's my solution with Robolectric.
#ExperimentalCoroutinesApi
#RunWith(RobolectricTestRunner::class)
class PreferenceDataSourceTest {
#get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
private val context = InstrumentationRegistry.getInstrumentation().targetContext
private lateinit var dataSource: PreferenceDataSource
private lateinit var dataStore: DataStore<UserPreferences>
#Before
fun setUp() {
Dispatchers.setMain(Dispatchers.Unconfined)
dataStore = DataStoreFactory.create(
serializer = UserPreferencesSerializer(),
scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()),
) {
context.dataStoreFile("test_user_preferences.pb")
}
dataSource = PreferenceDataSource(userPreferences = dataStore)
}
}
Hi I am trying to test livedata which is in my viewmodel, I have written to test to verify that the repository call has been made
how can I check if the live data object in this case, and what additional test cases I should be writing for this code in viewModel
Thanks
R
MainActivityViewModel
class MainActivityViewModel #Inject constructor(
private val dataRepository: DataRepository
): ViewModel() {
val _charactersLiveData = MutableLiveData<Result<ArrayList<Character>>>()
val charactersLiveData: LiveData<Result<ArrayList<Character>>> = _charactersLiveData
fun fetchCharacters() {
viewModelScope.launch {
_charactersLiveData.value = dataRepository.getCharacters()
}
}
}
MainActivityViewModelTest
#RunWith(MockitoJUnitRunner::class)
class MainActivityViewModelTest {
#get:Rule
val coroutineRule = MainCoroutineRule()
#Mock
private lateinit var dataRepository: DataRepository
#InjectMocks
private lateinit var mainActivityViewModel: MainActivityViewModel
#Test
fun fetchCharacters() {
runBlockingTest {
mainActivityViewModel.fetchCharacters()
verify(dataRepository).getCharacters()
}
}
}
You can reference this article: https://medium.com/androiddevelopers/unit-testing-livedata-and-other-common-observability-problems-bb477262eb04
The main idea here is:
Mock dataRepository
When dataRepository calls getCharacters(), it should return the testing value. E.g. listOf('a')
Execute mainActivityViewModel.fetchCharacters()
Expect the value of your live data
assertEquals(mainActivityViewModel.charactersLiveData.getOrAwaitValue(), listOf('a'))
Try this if any issues then let me know. I have try to do according to your class and data but if you need then can changes.
#RunWith(MockitoJUnitRunner::class)
class MainActivityViewModelTest {
#get:Rule
val coroutineRule = MainCoroutineRule()
#Mock
private lateinit var dataRepository: DataRepository
#InjectMocks
private lateinit var mainActivityViewModel: MainActivityViewModel
#Mock
private lateinit var dataObserver: Observer<Result<List<Character>>>
#Test
fun fetchCharacters() {
runBlockingTest {
Mockito.`when`(datarepository).getcharacter()
.thenreturn(Result.success(listOf(Character (
Name=A,
Type=hero))))
mainActivityViewModel.fetchCharacters()
mainActivityViewModel.charactersLiveData.observeForever(dataObserver)
Mockito.verify(dataRepository).getCharacters()
Mockito.verify(dataObserver).onChanged(Result.success(listOf(Character (
Name=A,
Type=hero))))
mainActivityViewModel.charactersLiveData.removeObserver(dataObserver)
}
}
}
So I have a class
class Test<T : SomeListener> #Inject constructor(
private val dependency1: Dependency1,
private val listener: T
)
I'm trying to write a unit test for it using mockk and running into an error when trying to mock and initialize it with the generic type.
class TestTest {
#MockK
lateinit var dependency1: Dependency1
#MockK
lateinit var listener: ListenerImpl
#InjectMockKs(overrideValues = true)
lateinit var testObject: Test<ListenerImpl>
}
I keep getting an error "io.mockk.MockKException: No matching constructors found: ... listener : T =
What is the right way to get it to mock the constructor correctly with this generic parameter value?
Unfortunately I wasn't able to figure out a way to purely do it with annotations. What I ended up doing was:
class TestTest {
#MockK
lateinit var dependency1: Dependency1
#MockK
lateinit var listener: ListenerImpl
lateinit var testObject: Test<SomeListener>
#BeforeEach
fun setUp() {
testObject = Test(
dependency1,
listener
)
}
}
This worked and initialized the testObject correctly.
i'm try to test my ViewModel with mockito.
This is my TestClass:
#RunWith(JUnit4::class)
class RatesViewModelTest {
#Rule #JvmField
open val instantExecutorRule = InstantTaskExecutorRule()
#Mock
var observer: Observer<Pair<ArrayList<CurrencyExchangerModel>,Boolean>>? = null
#Mock
private lateinit var repository: RatesRepository
private var currencyList = ArrayList<CurrencyModel>()
private lateinit var viewModel : RatesViewModel
#Before
fun setUp(){
MockitoAnnotations.initMocks(this)
currencyList.add(CurrencyModel("BASE"))
viewModel = RatesViewModel(repository!!)
viewModel.getCurrencyExchangerObservableList().observeForever(observer!!)
}
#Test
fun testNull(){
Mockito.`when`(repository.getFlowableRates()).thenReturn( Flowable.just(currencyList) )
assertTrue(viewModel.getCurrencyExchangerObservableList().hasObservers())
}
}
When this method is invoked:
Mockito.`when`(repository.getFlowableRates()).thenReturn( Flowable.just(currencyList) )
I got this error:
kotlin.UninitializedPropertyAccessException: lateinit property db has
not been initialized
Here the repository:
open class RatesRepository(context:Context) : BaseRepository(context){
#Inject
lateinit var ratesAPI: RatesAPI
#Inject
lateinit var db: Database
/**
* load the updated chatList from API
*/
fun loadCurrencyRatesFromAPI(): Single<ArrayList<CurrencyModel>> {
val supportedCurrency = context.resources.getStringArray(R.array.currencies)
return ratesAPI.getLatestRates(EUR_CURRENCY_ID).map { RatesConverter.getRatesListFromDTO(it,supportedCurrency) }
}
/**
* save rates on DB
*/
fun saveCurrencyRatesOnDB(list:ArrayList<CurrencyModel>): Completable {
return db.currencyRatesDAO().insertAll(list)
}
/**
* get flawable rates from DB
*/
fun getFlowableRates(): Flowable<List<CurrencyModel>> {
return db.currencyRatesDAO().getAll()
}
companion object {
const val EUR_CURRENCY_ID = "EUR" //BASE
}
}
What i'm doing wrong ?
Thx !
When you define behaviour of a mock and use the when(...).then(...) notation of mockito,
the method itself is invoked (by mockito, normally not relevant for your test).
In your case that is a problem because db is not initialized.
To avoid this issues use the doReturn(...).when(...) syntax in these cases,
which does not cause the method invocation.
Mockito.doReturn(Flowable.just(currencyList)).when(repository).getFlowableRates();
(You might need to adjust this java syntax to make it kotlin compatible)
i have this test class running with MockitoJUnitRunner before and then i added RoboLectric, now i use RobolectricTestRunner
So the first thing it tryed is running my old tests but just changing the runner and the test now always fail. I do not really understand what is happening here, i am just trying to make my old test work with RobolectricTestRunner without stop using Mockito.
My Code before changing to RoboLectric (TEST PASS SUCCESSFULLY)
#RunWith(MockitoJUnitRunner::class)
class LauncherViewModelTest {
companion object {
#ClassRule
#JvmField
val schedulers = RxImmediateeSchedulerRule()
}
#Rule
#JvmField
val rule = InstantTaskExecutorRule()
#Mock
private lateinit var mockContext: MyApplication
#Mock
private lateinit var mockedDatabase: MyDatabase
#Mock
private lateinit var session: Session
//
#Mock
lateinit var mockedDatabaseRxWrapper: DatabaseRxWrapper
/** Evaluated class **/
#InjectMocks
lateinit var launcherViewModel: LauncherViewModel
#Test
fun checkIfHasSessionSuccess() {
val sessionFlowable: Flowable<Session> = Flowable.fromCallable { session }
FieldSetter.setField(launcherViewModel,
launcherViewModel.javaClass.getDeclaredField("databaseRxWrapper"), mockedDatabaseRxWrapper)
doReturn(sessionFlowable).`when`(mockedDatabaseRxWrapper).getSession()
launcherViewModel.checkIfHasSession()
//$hasSession is a mutable live data
Assert.assertEquals(true, launcherViewModel.hasSession.value)
}
}
My Code after changing to RoboLectric : (DatabaseRxWrapper.getSession() returns always null even when i use Mockito.doReturn().when())
#RunWith(RobolectricTestRunner::class)
class LauncherViewModelTest {
companion object {
#ClassRule
#JvmField
val schedulers = RxImmediateeSchedulerRule()
}
#Rule
#JvmField
val rule = InstantTaskExecutorRule()
#get:Rule
val mockitoRule = MockitoJUnit.rule()
#Mock
private lateinit var mockContext: MyApplication
#Mock
private lateinit var mockedDatabase: MyDatabase
#Mock
private lateinit var session: Session
//
#Mock
lateinit var mockedDatabaseRxWrapper: DatabaseRxWrapper
/** Evaluated class **/
#InjectMocks
lateinit var launcherViewModel: LauncherViewModel
#Test
fun checkIfHasSessionSuccess() {
val sessionFlowable: Flowable<Session> = Flowable.fromCallable { session }
FieldSetter.setField(launcherViewModel,
launcherViewModel.javaClass.getDeclaredField("databaseRxWrapper"), mockedDatabaseRxWrapper)
doReturn(sessionFlowable).`when`(mockedDatabaseRxWrapper).getSession()
launcherViewModel.checkIfHasSession()
//$hasSession is a mutable live data
Assert.assertEquals(true, launcherViewModel.hasSession.value)
}
}
Class under Test
class LauncherViewModel(application: Application) : AndroidViewModel(application) {
#Inject
lateinit var databaseRxWrapper: DatabaseRxWrapper
val hasSession: MutableLiveData<Boolean> = MutableLiveData()
val application by lazy { getApplication<MyApplication>() }
init {
application.getAppComponent()?.inject(this)
}
fun saveLocation(location: Location) = sharedPreferenceManager.saveLocation(location)
fun checkIfHasSession() {
databaseRxWrapper.getSession()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
hasSession.postValue(true)
}, {
hasSession.postValue(false)
})
}
}
I found that you don't need the rule for rewriting the configuration of RX if you are running with Robolectric
So the code worked after deleting this classrule:
companion object {
#ClassRule
#JvmField
val schedulers = RxImmediateeSchedulerRule()
}