Android 仪器测试中的 Dagger 2 注入

Dan*_*der 2 java android dagger-2 instrumented-test

我正在尝试在 Android 仪器测试中使用 Dagger 2 进行 DI。它对于主应用程序组件中的类/活动/片段工作得很好,但我的测试组件似乎缺少一些我找不到的绑定。任何有关如何进行的想法将不胜感激。我的代码如下所示:

资产库测试

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
    }
}
Run Code Online (Sandbox Code Playgroud)

运行仪器测试时出现以下异常:

java.lang.IllegalArgumentException: No injector factory bound for Class<AssetRepositoryTest.PopulatedDatabaseInstance>
Run Code Online (Sandbox Code Playgroud)

与匕首相关的代码如下:

测试组件

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        TestPersistenceModule.class
})
public interface TestComponent extends AndroidInjector<TestApplication> {

    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<TestApplication> {
    }
}
Run Code Online (Sandbox Code Playgroud)

测试持久性模块

@Module(includes = TestRoomModule.class)
public abstract class TestPersistenceModule {

    @Binds
    abstract AssetRepository bindAssetRepository(final AssetRepositoryImpl repository);
}
Run Code Online (Sandbox Code Playgroud)

测试室模块

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试应用

public class TestApplication extends DaggerApplication {

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerTestComponent.builder().create(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

除此之外,我有一个自定义AndroidJUnitRunner扩展类,它重写该newApplication方法并返回TestApplication测试用例的实例。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我未在此处粘贴的类@Inject在其构造函数中具有注释,并且此代码在具有相应主模块和组件的主应用程序中正常工作。

As a final thought, the AssetRepositoryTest.PopulatedDatabaseInstace, which is instantiated by JUnit, is therefore not instantiated by Dagger and, to my knowledge, that seems to be the problem here.

How can I tell Dagger how to inject these fields into my JUnit test class?

Sha*_*awn 5

似乎您在匕首设置中缺少一些步骤,我已经提供了我使用的清单。

  • 创建自定义测试运行器
class MyCustomTestRunner : AndroidJUnitRunner() {

    override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
        return super.newApplication(cl, MyTestApplication::class.java.name, context)
    }
}

Run Code Online (Sandbox Code Playgroud)
  • 添加到测试运行程序到 app/build.gradle
android {
    ...
    defaultConfig {
        ...
        testInstrumentationRunner "com.example.android.dagger.MyCustomTestRunner"
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)
  • kapt 需要对 AndroidTest 源集进行操作。
...
dependencies {
    ...
    kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version"
}

Run Code Online (Sandbox Code Playgroud)
  • 创建测试模块
  • 创建测试应用组件。
  • 主应用程序应该看起来像这样
open class MyApplication : Application() {

    val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.factory().create(applicationContext)
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 测试应用
class MyTestApplication : MyApplication() {

    override fun initializeComponent(): AppComponent {
        // Creates a new TestAppComponent that injects fakes types
        return DaggerTestAppComponent.create()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您正在寻找有关每个步骤的更多详细信息,您可以在此处找到该信息。