代码之家  ›  专栏  ›  技术社区  ›  silentsudo

Dagger2注入单元测试为空

  •  0
  • silentsudo  · 技术社区  · 7 年前

    嗨,我用匕首为依赖注入的网络模块,应用程序模块,数据库模块,演示者和互动在我的应用程序。 我想在单元测试期间使用这些相同的类和模块。

    作为单元测试参考,我使用以下代码创建了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总是空的,因为 setUp 方法我已经注入了AndroidTestApplication类而不是 ExampleInstrumentedTest

    2 回复  |  直到 7 年前
        1
  •  0
  •   Tuby    7 年前

    实际上,您并没有在测试类中注入任何内容。 DaggerAndroidTestAppComponent.builder().create(application).inject(application); 你正在注射 AndroidTestApplication 而不是你的测试。

    尝试添加

    void inject(ExampleInstrumentedTest test);

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

    在这里,您正在创建匕首组件,无需在测试中再次执行。 制造 androidInjector AndroidTestAppComponent 而不是 AndroidInjector 在你的 AndroidTestApplicaiton ,为您的 AndroidTestApplication应用程序 然后在你的测试中 setUp application.getComponent().inject(this); 这样,您就可以将依赖项注入到所需的类中,该类就是您的测试。

        2
  •  0
  •   silentsudo    7 年前

    我不得不修改 @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) @组成部分 接口。

    我的测试类现在看起来像这样,我可以运行测试并获得覆盖率[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());
        }
    
    }
    
    推荐文章