Dagger 2 How to inject object into test

Viewed 3100

I would like to use my realm manager into unit test module. I did

@Singleton
@Component(modules = {
        TestApplicationModule.class,
        AndroidSupportInjectionModule.class,
        TestStoreDataModule.class,
        TestUtilsModule.class})
public interface AppComponentTest extends AppComponent {

    @Component.Builder
    interface Builder {

        @BindsInstance
        AppComponentTest.Builder application(Application application);

        AppComponentTest build();
    }
}

and then I want to achieve

@RunWith(RobolectricTestRunner.class)
@Config(application = TestVerioriApplication.class, sdk=27)
public class BaseVerificationQuestionnaireFragmentTest {

    @Inject
    RealmManager realmManager;
}

But realmManager is null. How to use dagger 2 to write simple module test ? I used dagger-mock but it does not help. My module contains

@Module(includes = StoreDataModule.class)
public class TestStoreDataModule {

    @Provides
    @Singleton
    public static RealmConfiguration provideRealmConfiguration(RealmConstants realmConstants) {
        return new RealmConfiguration.Builder()
                .name(realmConstants.getName())
                .encryptionKey("Implement this key".getBytes())
                .schemaVersion(realmConstants.getSchemaVersion())
                .build();
    }

    @Provides
    @Singleton
    public static RealmManager provideRealmManager(RealmConfiguration realmConfiguration, SchedulerProvider schedulerProvider) {
        return new RealmManager(realmConfiguration, schedulerProvider);
    }

}

I tried everything from google, but I don't know how to inject object from graph.

2 Answers

Override your Application class, where you will replace dagger component instance by your TestComponent. Then create your own test runner by overriding AndroidJUnitRunner class where you need to add test application:

class TestRunner : AndroidJUnitRunner() {
   @Throws(InstantiationException::class,IllegalAccessException::class,ClassNotFoundException::class)
 override fun newApplication(cl:ClassLoader,className:String, context:Context):Application {
        return super.newApplication(cl, TestApplication::class.java.name, context)
  }
}

Next register your runner in build.gradle file :

testInstrumentationRunner "com.test.YourTestRunner"

Now you can just replace the implementation of a module that you want to change in test in your test component.

Ok. BaseVerificationQuestionnaireFragmentTest requests a field injection, but it is not injected itself. For this, AppComponentTest interface must have this1 line:

public void inject(BaseVerificationQuestionnaireFragmentTest baseVerificationQuestionnaireFragmentTest);

And then this method must be used in somewhere like @Before:

TestApplication app = (TestApplication) RuntimeEnvironment.systemContext;
app.appComponentTest.inject(this);

That assumes appComponentTest is public in TestApplication.

I successfully injected a ViewModel in its test this way.

Pardon my Java.


1 In my case Dagger stuff was located in sharedTest directory and could not see BaseVerificationQuestionnaireFragmentTest. I created an InjectableTest class that my test inherited from, and requested injection in the init block of the InjectableTest (that was Kotlin code).

Related