Search code examples
androidunit-testingmockitoandroid-viewmodel

Android mocking applicationcontext inside application


I am having trouble creating a test class. Basically I want to test my view model class which performs network call. The class network component is injected by using dagger needs the context parameter to check connection, this is my view model:

class MyViewModel(application: Application): AndroidViewModel(application) {
   @Inject lateinit var network: NetworkService
    init {
        DaggerNetworkComponent.builder().networkModule(NetworkModule(application.applicationContext))
        .build().inject(this)
        network.callNetwork()
    } 
}

And the test class is something like

lateinit var myViewModel: MyViewModel
@Test
fun testMyNetwork() { 
   application =  Mockito.mock(Application::class.java)
   myViewModel = MyViewModel(application)
}

The application.applicationContext always returns null which then returns IllegalStateException

Is there any solution for this?


Solution

  • I think there are two possibilities here. I used 2nd one and know it works, 1st one is my guess.

    (1)

    You are mocking Application. Then you are trying to use its applicationContext however you did not mock it. You need to mock it as well:

    val context  =  Mockito.mock(Context::class.java)
    Mockito.`when`(application.applicationContext).thenReturn(context)
    

    (2)

    Assume 1) your test is instrumentation test 2) you are using subclass of Application - say, MyApplication.

    You will then have to create its subclass - say, TestMyApplication. Next step would be to create subclass of AndroidJUnitRunner, may be like this:

    public class MyInstrumentationTestRunner extends AndroidJUnitRunner {
        @Override
        public Application newApplication(ClassLoader cl, String className, Context context)
                throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            return Instrumentation.newApplication(TestMyApplication.class, context);
        }
    }
    

    Finally, you need to tell android to use this runner:

    allprojects {
        ext {
            ....
            testInstrumentationRunner = "com...MyInstrumentationTestRunner"
        }
    }
    
    

    As a result of the above, application context will be instance of TestMyApplication across your instrumentation tests.