I am running into the following exception when running a test for a composable that injects a hilt view model, eg:
@Composable
fun MyScreen(
viewModel: MyViewModel = hiltViewModel()
) {
}
Following the hilt testing documentation here: https://developer.android.com/training/dependency-injection/hilt-testing
I have the following test:
@HiltAndroidTest
class MyComposeTest {
@get:Rule(order = 0)
var hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val composeRule = createComposeRule()
@Before
fun setup() {
hiltRule.inject()
}
@Test
fun canary() {
// This test fails with exception
}
}
With a custom test runner:
class CustomTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Use in build.gradle:
android {
defaultConfig {
// Replace com.example.android.dagger with your class path.
testInstrumentationRunner "com.example.android.dagger.CustomTestRunner"
}
}
Looks like the first place it dies is in my AppInitializer, which handle androidx.startup initialization.
@EntryPoint
@InstallIn(SingletonComponent::class)
interface AppInitializer {
companion object {
// Resolve the InitializerEntryPoint from a context
fun resolve(context: Context): AppInitializer {
val appContext = context.applicationContext ?: throw IllegalStateException()
return EntryPointAccessors.fromApplication(
appContext,
AppInitializer::class.java
)
}
}
fun inject(workManagerInitializer: WorkManagerInitializer)
fun inject(otherInitializer: OtherInitializer)
}
Exception:
java.lang.RuntimeException: Unable to get provider androidx.startup.InitializationProvider: androidx.startup.StartupException: androidx.startup.StartupException: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
...
Caused by: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
at dagger.hilt.internal.Preconditions.checkState(Preconditions.java:83)
at dagger.hilt.android.internal.testing.TestApplicationComponentManager.generatedComponent(TestApplicationComponentManager.java:96)
at dagger.hilt.android.testing.HiltTestApplication.generatedComponent(HiltTestApplication.java:50)
at dagger.hilt.EntryPoints.get(EntryPoints.java:59)
at dagger.hilt.android.EntryPointAccessors.fromApplication(EntryPointAccessors.kt:35)
at com.test.AppInitializer$Companion.resolve(AppInitializer.kt:27)
EDIT:
To get past this I had to use @EarlyEntryPoint and EarlyEntryPoints.get(appContext, AppInitializer::class.java).
That did get me further, however I am still running into an issue with hilt injecting the viewmodel into the composable. eg
@Composable
fun MyScreen(
viewModel: MyViewModel = hiltViewModel()
) {
}
The following exception is thrown:
java.lang.RuntimeException: Cannot create an instance of class com.test.MyViewModel
Given my setup should hilt properly inject the viewModel into the composable? Or is there something else I need to do?