Search code examples
androidunit-testingkotlinmockitomockito-kotlin

Cannot instantiate @InjectMocks field named 'viewModel' of type 'class com.example.digiandroidapp.viewmodel.CarViewModel'?


I am developing android app and I have implemented mockito in my viewmodel class in android but when I run the test I am getting following exceptions

org.mockito.exceptions.misusing.InjectMocksException: 
Cannot instantiate @InjectMocks field named 'viewModel' of type 'class com.example.digiandroidapp.viewmodel.CarViewModel'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : Parameter specified as non-null is null: method com.example.digiandroidapp.viewmodel.CarViewModel.<init>, parameter carsInfoDao


    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method com.example.digiandroidapp.viewmodel.CarViewModel.<init>, parameter carsInfoDao
    at com.example.digiandroidapp.viewmodel.CarViewModel.<init>(CarViewModel.kt)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at org.mockito.internal.util.reflection.ReflectionMemberAccessor.lambda$newInstance$0(ReflectionMemberAccessor.java:29)
    at org.mockito.internal.util.reflection.ReflectionMemberAccessor.newInstance(ReflectionMemberAccessor.java:29)
    at org.mockito.internal.util.reflection.ReflectionMemberAccessor.newInstance(ReflectionMemberAccessor.java:20)
    at org.mockito.internal.util.reflection.FieldInitializer$ParameterizedConstructorInstantiator.instantiate(FieldInitializer.java:287)
    at org.mockito.internal.util.reflection.FieldInitializer.acquireFieldInstance(FieldInitializer.java:146)
    at org.mockito.internal.util.reflection.FieldInitializer.initialize(FieldInitializer.java:91)
    at org.mockito.internal.configuration.injection.ConstructorInjection.processInjection(ConstructorInjection.java:48)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:68)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.relayProcessToNextStrategy(MockInjectionStrategy.java:91)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:71)
    at org.mockito.internal.configuration.injection.MockInjection$OngoingMockInjection.apply(MockInjection.java:88)
    at org.mockito.internal.configuration.DefaultInjectionEngine.injectMocksOnFields(DefaultInjectionEngine.java:26)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.injectCloseableMocks(InjectingAnnotationEngine.java:119)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.processInjectMocks(InjectingAnnotationEngine.java:62)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:49)
    at org.mockito.MockitoAnnotations.openMocks(MockitoAnnotations.java:82)
    at org.mockito.internal.framework.DefaultMockitoSession.<init>(DefaultMockitoSession.java:43)
    at org.mockito.internal.session.DefaultMockitoSessionBuilder.startMocking(DefaultMockitoSessionBuilder.java:83)
    at org.mockito.internal.junit.JUnitSessionStore$1.evaluate(JUnitSessionStore.java:38)

below my CarViewModel.kt

class CarViewModel(
    private val api: ApiInterface,
    private val carsInfoDao: CarsInfoDao,
    private val carsLocationDao: CarsLocationDao,
) : ViewModel() {
    private val _cars = MutableLiveData<List<CarInfo>>()
    val cars: LiveData<List<CarInfo>> = _cars

    private val _error = SingleLiveEvent<Exception>()
    val error: LiveData<Exception> = _error

    private val _loading = MutableLiveData<Boolean>()
    val loading: LiveData<Boolean> = _loading



    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    fun getAllCars() {
        viewModelScope.launch {
            try {
                val result = api.getAllCars()
                println("dataaaa -> $result")
                _loading.value = true
                _cars.value = result
                val carsInfoList = mutableListOf<CarsInfoEntity>()
                val carsLocationList = mutableListOf<CarsLocationEntity>()
                result.forEach { carsInfo: CarInfo ->
                    carsInfoList.add(
                        CarsInfoEntity(
                            carsInfo.id,
                            carsInfo.brand,
                            carsInfo.model,
                            carsInfo.imageURL,
                            carsInfo.fuel,
                            carsInfo.pricePerDay,
                            carsInfo.currency,
                            carsInfo.year,
                            carsInfo.type,
                            carsInfo.status,
                            carsInfo.groupId,
                            carsInfo.registrationPlate,
                            carsInfo.createdAt,
                            carsInfo.updatedAt,
                            carsInfo.subjectTypeId
                        )
                    )
                    carsLocationList.add(
                        CarsLocationEntity(
                            carsInfo.id,
                            carsInfo.location.latitude,
                            carsInfo.location.longitude,
                        )
                    )
                }
                carsInfoDao.insertCarsInfo(carsInfoList)
                carsLocationDao.insertCarsLocation(carsLocationList)
            } catch (e: Exception) {
                _error.value = e
            } finally {
                _loading.value = false
            }
        }
    }

}

below ViewModelTest

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

    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @InjectMocks
    private lateinit var viewModel: CarViewModel

    @Mock
    private lateinit var api: ApiInterface
    @Mock
    private lateinit var cars: List<CarInfo>

    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setup() {
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }


    @Test
    fun `get cars positive case`() {
        val cardData = cars

        observe(viewModel.cars)

        wheneverBlocking { api.getAllCars() }.thenReturn(cardData)

        viewModel.getAllCars()

        assert(viewModel.cars.value == cardData)
    }


    @Test
    fun `get cars negative case`() {
        val userObserver = observe(viewModel.cars)
        val errorObserver = observe(viewModel.error)

        val exception = IOException("404")
        wheneverBlocking { api.getAllCars() }.thenThrow(exception)

        viewModel.getAllCars()

        assert(viewModel.error.value == exception)

        verifyZeroInteractions(userObserver)
        verify(errorObserver).onChanged(exception)
    }


}
  1. Invalidate cache restart 2.Followed following answers Cannot instantiate @InjectMocks field named exception with java class

I want to know what is causing an issue what I have to do in order to avoid exceptions I have followed many stackoverflow post it did not solve my issue


Solution

  • I fixed by adding MockitoAnnotations.initMocks(this) to setup method