Search code examples
androidkotlindagger-2daggermockk

Dagger not injecting activity


I am currently working my way through this article, trying to mock dagger dependencies in android with Kotlin but am having some trouble.

I am receiving an error saying activityInjector is not initialised.

What am I doing wrong?

TestAppComponent

@Singleton
@Component(
    modules = [
        AndroidSupportInjectionModule::class,
        TestAppModule::class,
        ActivityModule::class,
        FragmentModule::class,
        ViewModelModule::class
    ]
)
interface TestAppComponent : AndroidInjector<TestApp> {

    @Component.Builder
    abstract class Builder : AndroidInjector.Builder<TestApp>() {
        abstract fun appModule(appModule: TestAppModule): Builder
    }
}

TestApp

class TestApp: Application(), HasActivityInjector {

    @Inject
    lateinit var activityInjector: DispatchingAndroidInjector<Activity>

    override fun activityInjector(): AndroidInjector<Activity>  = activityInjector
}

Test Injector

class TestInjector(private val testAppModule: TestAppModule) {

    fun inject() {
        val testApp= ApplicationProvider.getApplicationContext() as TestApp

        DaggerTestAppComponent
            .builder()
            .appModule(testAppModule)
            .create(testApp)
            .inject(testApp)
    }
}

Activity Module

@Module
abstract class ActivityModule {
    @ContributesAndroidInjector
    abstract fun provideNavigationActivity(): NavigationActivity
}

Instrumented Unit Test

@Rule
@JvmField
var navigationActivityTestRule = ActivityTestRule(NavigationActivity::class.java, true, true)

@MockK
private lateinit var repo: Repo

@Before
fun setUp() {
    MockKAnnotations.init(this)

    TestInjector(TestAppModule(repo)).inject()
}

Solution

  • Because of the ActivityTestRule your activity is launched even before the TestInjector is called from your setup method. You need to defer activity launch until your DaggerTestAppComponent is built.

    Try this:

    @Rule
    @JvmField
    var navigationActivityTestRule = ActivityTestRule(NavigationActivity::class.java, true, false) 
    // ^^ Notice the third parameter here, passing false will not launch the activity
    
    @MockK
    private lateinit var repo: Repo
    
    @Before
    fun setUp() {
        MockKAnnotations.init(this)
        TestInjector(TestAppModule(repo)).inject()
    
        // Launch the activity now that TestInjector is called
        navigationActivityTestRule.launchActivity(Intent()) 
    }