Android 仪器测试中的 Dagger 2 注入

Posted

技术标签:

【中文标题】Android 仪器测试中的 Dagger 2 注入【英文标题】:Dagger 2 injection in Android instrumentation tests 【发布时间】:2021-10-16 22:33:24 【问题描述】:

我正在尝试在我的 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>

而匕首相关代码如下:

测试组件

@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 测试类中?

【问题讨论】:

【参考方案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()
    

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

【讨论】:

以上是关于Android 仪器测试中的 Dagger 2 注入的主要内容,如果未能解决你的问题,请参考以下文章

Android 上的 Dagger 2,缺少错误消息

如何在 android 中使用 dagger 对 kotlin 文件进行 UI 测试?

单元/仪器测试 Android Gradle。仪器测试不会运行

Kapt 不适用于 Android Studio 3.0 中的 AutoValue

有啥解决方案可以解决android上的仪器测试

使用 Gradle 运行特定的 Android 仪器测试