【问题标题】:Dagger2 Injection Unit Tests is nullDagger2 注入单元测试为空
【发布时间】:2018-11-01 21:28:19
【问题描述】:

您好,我在我的应用程序中使用 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) t 这里采用核心 android 模块,所以当我在我的 Activity 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 对象。 谢谢。

【问题讨论】:

    标签: android dagger-2 android-instrumentation dagger


    【解决方案1】:

    你实际上并没有在你的 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 组件,无需在测试中再次执行此操作。 将androidInjector 设为AndroidTestAppComponent 而不是AndroidTestApplicaiton 中的AndroidInjector,在AndroidTestApplication 中为该组件创建一个getter,然后在测试setUp 方法中使用application.getComponent().inject(this); 这样您就可以将依赖项注入所需的类,即您的测试。

    【讨论】:

    • 如前所述,我知道我没有在测试类中注入任何东西,我想要一种方法来注入它Ideally, apppref is alwyas null,,谢谢 tuby,让我试试你的方法。
    • 直到我到达这里stackoverflow.com/questions/50580389/… 不一定是它,但它是我需要实现的参考。谢谢你,我会发布我的答案。
    【解决方案2】:

    我不得不修改@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());
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2015-05-29
      • 2019-01-13
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多