Dagger2注射单元测试为空

时间:2018-11-01 10:35:22

标签: android dagger-2 android-instrumentation dagger

嗨,我在我的应用程序中使用了匕首来进行网络模块,ApplicationModule,DatabaseModule,Presenter和交互器的依赖项注入。 我想在单元测试期间使用这些相同的类和模块。

作为单元测试参考,我使用以下代码创建了AndroidTestAppComponent:

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        AndroidTestAppModule.class,
        NetworkModule.class
})
public interface AndroidTestAppComponent extends AndroidInjector<AndroidTestApplication> {
    @Component.Builder
    abstract class AndroidTestAppComponentBuilder extends Builder<AndroidTestApplication> {
    }
}

提供所有模块超出此问题的范围,请考虑AndroidTestAppModule.java below

public class AndroidTestAppModule {
    @Provides
    @Singleton
    Context provideContext(AndroidTestApplication application) {
        return application.getApplicationContext();
    }

    @Singleton
    @Provides
    KeyguardManager provideKeyguardManager(Context context) {
        return (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
    }

    @Singleton
    @Provides
    FingerprintManagerCompat providerFingerPrintManager(Context context) {
        return FingerprintManagerCompat.from(context);
    }
}

我能够生成DaggerAndroidTestAppComponent。 我的应用程序类如下:

public class AndroidTestApplication extends DaggerApplication implements HasActivityInjector {
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

    AndroidInjector<AndroidTestApplication> androidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        androidInjector.inject(this);
    }

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        androidInjector = DaggerAndroidTestAppComponent.builder().create(this);
        return androidInjector;
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return dispatchingActivityInjector;
    }
}

其他AppPref.java

@Singleton
public class AppPref {

    private SharedPreferences preferences;

    @Inject
    AppPref(Context context) {
        preferences = context.getSharedPreferences("somefile", Activity.MODE_PRIVATE);
    }
}

从文档中读到:AndroidInjection#inject(T t)这里需要核心的android模块,因此当我在活动AndroidInjection.inject(activity_reference_usually__this__)中调用它时,它可以正常工作(正常情况,实际构建且没有测试应用)

在不更改大量代码的情况下,如何在AndroidInstrumentationTest中使用这些类,因为我只会在测试包内的Test**DaggerModules中更改测试实现。

用于检测的示例代码如下:

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {


    AndroidTestApplication application;

    @Inject
    AppPref appPref;


    @Before
    public void setUp() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Context appContext = InstrumentationRegistry.getTargetContext();
        application = (AndroidTestApplication) Instrumentation.newApplication(AndroidTestApplication.class, appContext);
        DaggerAndroidTestAppComponent.builder().create(application).inject(application);
    }

    @Test
    public void useAppContext() {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.a.b", appContext.getPackageName());
    }

    @Test
    public void testPreNotNUll() {
        Assert.assertNotNull(appPref);
    }

}

理想情况下,apppref始终为null,因为在setUp方法中我注入了AndroidTestApplication类,而不是在ExampleInstrumentedTest中注入了我如何编辑dagger2代码,以便@Inject正常工作并获得有效的appPref对象。 谢谢。

2 个答案:

答案 0 :(得分:0)

您实际上没有在Test类中注入任何东西。 DaggerAndroidTestAppComponent.builder().create(application).inject(application); 您正在注入AndroidTestApplication而不是测试。

尝试添加

void inject(ExampleInstrumentedTest test);

进入您的组件界面。

@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
    androidInjector = DaggerAndroidTestAppComponent.builder().create(this);
    return androidInjector;
}

这里您正在创建Dagger组件,无需在测试中再次进行。 使{{1}中的androidInjector成为AndroidTestAppComponent,而不是AndroidInjector,在AndroidTestApplicaiton中使该组件吸气,然后在测试{{1}中}方法使用AndroidTestApplication 这样,您就可以将依赖项注入所需的类(即Test)中。

答案 1 :(得分:0)

我不得不修改@Component界面,以跳过从AndroidInjector.Builder扩展生成器的过程,并提供自己的方法。

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        AndroidTestAppModule.class,
        NetworkModule.class
})
public interface AndroidTestAppComponent extends AndroidInjector<AndroidTestApplication> {
    void inject(ExampleInstrumentedTest test);

    @Component.Builder
    abstract class AndroidTestAppComponentBuilder {
        @BindsInstance
        public abstract AndroidTestAppComponentBuilder application(AndroidTestApplication application);

        public abstract AndroidTestAppComponent build();
    }
}

我不得不手动传递应用程序并构建组件,然后,如tuby所建议的,我不得不向void inject(ExampleInstrumentedTest test)接口添加新方法@Component

我的测试类现在看起来像这样,我可以运行测试并获得覆盖率[jacoco工具]:

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {


    @Inject
    AppPref appPref;


    @Before
    public void setUp() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Context appContext = InstrumentationRegistry.getTargetContext();
        AndroidTestApplication application = (AndroidTestApplication) Instrumentation
                .newApplication(AndroidTestApplication.class, appContext);
        DaggerAndroidTestAppComponent.builder().application(application)
                .build()
                .inject(this);

    }

    @Test
    public void test1AppPrefNotNUll() {
        Assert.assertNotNull(appPref);
    }


    private final String KEY = "key";
    private final String valid = "test_app";
    private final String invalid = "non_app";


    @Test
    public void test2AppPrefWrite() {
        appPref.writePreference(KEY, valid);
        Assert.assertNotNull(appPref.readPreference(KEY));
    }

    @Test
    public void test3AppPrefRead() {
        Assert.assertEquals(valid, appPref.readPreference(KEY));
    }

    @Test
    public void test4AppPrefInvalid() {
        Assert.assertNotNull(invalid, appPref.readPreference(KEY));
    }

    @Test
    public void test5AppPrefClear() {
        appPref.clearPreferences();
        Assert.assertEquals(0, appPref.size());
    }

}