Hilt injection with android instrumented tests

552 Views Asked by At

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?

0

There are 0 best solutions below