我试图在我的Android仪器测试中使用dagger2进行DI。它在主应用程序组件中的类/活动/片段工作得非常好,但我的测试组件似乎缺少一些我找不到的绑定。任何关于如何去做的想法将是感激的。我的代码看起来像这样:
AssetRepositoryTest
public class AssetRepositoryTest {
@Nested
@DisplayName("Given a populated database")
public class PopulatedDatabaseInstance {
@Inject
private TestDatabase database;
@Inject
private AssetRepository repository;
@BeforeEach
public void setup() {
final TestApplication application = ApplicationProvider.getApplicationContext();
application.androidInjector().inject(this);
// Setup database
}
// Tests
}
}
运行检测测试时,我得到以下异常:
java.lang.IllegalArgumentException: No injector factory bound for Class<AssetRepositoryTest.PopulatedDatabaseInstance>
,dagger相关代码如下:
TestComponent
@Singleton
@Component(modules = {
AndroidSupportInjectionModule.class,
TestPersistenceModule.class
})
public interface TestComponent extends AndroidInjector<TestApplication> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<TestApplication> {
}
}
TestPersistenceModule
@Module(includes = TestRoomModule.class)
public abstract class TestPersistenceModule {
@Binds
abstract AssetRepository bindAssetRepository(final AssetRepositoryImpl repository);
}
TestRoomModule
@Module
public class TestRoomModule {
@Provides
@Singleton
TestDatabase provideTestDatabase(final Application application) {
return Room.inMemoryDatabaseBuilder(application, TestDatabase.class).build();
}
@Provides
@Singleton
AssetDao provideAssetDao(final TestDatabase testDatabase) {
return testDatabase.getAssetDao();
}
}
TestApplication
public class TestApplication extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerTestComponent.builder().create(this);
}
}
除此之外,我有一个自定义的AndroidJUnitRunner
扩展类,它覆盖newApplication
方法并返回测试用例的TestApplication
实例。
我的AssetRepositoryImpl
如下:
AssetRepositoryImpl
@Singleton
public class AssetRepositoryImpl extends AbstractRepository<Asset, AssetEntity> implements AssetRepository {
@Inject
protected WorkspaceDao workspaceDao;
@Inject
public AssetRepositoryImpl(final AssetDao dao, final AssetMapper mapper) {
super(dao, mapper);
}
}
我没有粘贴在这里的类在它们的构造函数中有@Inject
注释,并且这些代码在主应用程序中与各自的主模块和组件一起正常工作。
作为最后一个想法,由JUnit实例化的AssetRepositoryTest.PopulatedDatabaseInstace
因此没有被Dagger实例化,据我所知,这似乎是这里的问题。
我如何告诉Dagger如何将这些字段注入我的JUnit测试类?
似乎你在dagger设置中缺少一些步骤,我已经包含了我使用的清单。
- 创建CustomTestRunner
class MyCustomTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, MyTestApplication::class.java.name, context)
}
}
- 添加到测试运行器到app/build.gradle
android {
...
defaultConfig {
...
testInstrumentationRunner "com.example.android.dagger.MyCustomTestRunner"
}
...
}
- kapt需要对AndroidTest源代码集进行操作。
...
dependencies {
...
kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version"
}
- 创建测试模块
- 创建TestAppComponent。
- 主应用程序应该看起来像这样
open class MyApplication : Application() {
val appComponent: AppComponent by lazy {
initializeComponent()
}
open fun initializeComponent(): AppComponent {
return DaggerAppComponent.factory().create(applicationContext)
}
}
- TestApplication
class MyTestApplication : MyApplication() {
override fun initializeComponent(): AppComponent {
// Creates a new TestAppComponent that injects fakes types
return DaggerTestAppComponent.create()
}
}
如果你想了解每个步骤的更多细节,你可以在这里找到相关信息。