Reputation: 1277
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?
Upvotes: 5
Views: 7803
Reputation: 3011
This can be achieved by using a Fake. supposed you want to mock the interface that being implemented by the Application class.
// main
interface AppInitializer {
val isUserLoggedIn: Boolean
}
class MyApplication : AppInitializer {
override val isUserLoggedIn: Boolean
get() = // ...
}
// test
class FakeMyApplication : AppInitializer {
override val isUserLoggedIn: Boolean
get() = true
// you need to override this
override fun getApplicationContext(): Context {
return this
}
}
Upvotes: 0
Reputation: 3500
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.
Upvotes: 3