Dagger2 注入单元测试为空
Dagger2 Injection Unit Tests is null
您好,我在我的应用程序中使用 dagger 对网络模块、ApplicationModule、DatabaseModule、Presenters 和交互器进行依赖注入。
我想在单元测试期间使用这些相同的 classes 和模块。
作为单元测试参考,我使用以下代码创建了 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
。
我的申请 class 如下:
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
class
@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 始终为空,因为在 setUp
方法中我注入了 AndroidTestApplication class 而不是在 ExampleInstrumentedTest
我如何编辑我的 dagger2 代码以便 @Inject 工作正常我得到有效的 appPref 对象。
谢谢。
你实际上并没有在你的测试中注入任何东西class。
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 组件,无需在测试中再次创建。
在你的 AndroidTestApplicaiton
中使 androidInjector
成为 AndroidTestAppComponent
而不是 AndroidInjector
,在你的 AndroidTestApplication
中为该组件创建一个 getter,然后在你的测试中setUp
方法使用 application.getComponent().inject(this);
这样你就可以将依赖项注入所需的 class 这是你的测试。
我不得不修改 @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
接口。
我的测试 class 现在看起来像这样,我能够 运行 测试并获得覆盖[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());
}
}
您好,我在我的应用程序中使用 dagger 对网络模块、ApplicationModule、DatabaseModule、Presenters 和交互器进行依赖注入。 我想在单元测试期间使用这些相同的 classes 和模块。
作为单元测试参考,我使用以下代码创建了 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
。
我的申请 class 如下:
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
class
@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 始终为空,因为在 setUp
方法中我注入了 AndroidTestApplication class 而不是在 ExampleInstrumentedTest
我如何编辑我的 dagger2 代码以便 @Inject 工作正常我得到有效的 appPref 对象。
谢谢。
你实际上并没有在你的测试中注入任何东西class。
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 组件,无需在测试中再次创建。
在你的 AndroidTestApplicaiton
中使 androidInjector
成为 AndroidTestAppComponent
而不是 AndroidInjector
,在你的 AndroidTestApplication
中为该组件创建一个 getter,然后在你的测试中setUp
方法使用 application.getComponent().inject(this);
这样你就可以将依赖项注入所需的 class 这是你的测试。
我不得不修改 @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
接口。
我的测试 class 现在看起来像这样,我能够 运行 测试并获得覆盖[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());
}
}