0

我正在尝试在我的 Android 仪器测试中将 Dagger 2 用于 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相关代码如下:

测试组件

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

    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<TestApplication> {
    }
}

测试持久性模块

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

    @Binds
    abstract AssetRepository bindAssetRepository(final AssetRepositoryImpl repository);
}

测试室模块

@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();
    }
}

测试应用

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在其构造函数中具有注释,并且此代码在具有各自主要模块和组件的主应用程序中正常工作。

作为最后的想法,AssetRepositoryTest.PopulatedDatabaseInstace由 JUnit 实例化的 . 因此不是由 Dagger 实例化的,据我所知,这似乎是这里的问题。

如何告诉 Dagger 如何将这些字段注入到我的 JUnit 测试类中?

4

1 回答 1

1

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

  • 创建 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)
    }
}
  • 测试应用
class MyTestApplication : MyApplication() {

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

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

于 2021-08-13T18:33:52.770 回答