#java #android #dagger-2 #instrumented-test
Вопрос:
Я пытаюсь использовать Dagger 2 для DI в своих тестах инструментов для Android. Он отлично работает для классов/действий/фрагментов в основном компоненте приложения, но в моем тестовом компоненте, похоже, отсутствуют некоторые привязки, которые я не могу найти. Любые идеи о том, как это сделать, будут оценены по достоинству. Код, который у меня есть, выглядит так:
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> {
}
}
Модуль тестируемости
@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();
}
}
Тестовое приложение
public class TestApplication extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerTestComponent.builder().create(this);
}
}
Кроме того, у меня есть пользовательский AndroidJUnitRunner
класс расширения, который переопределяет newApplication
метод и возвращает TestApplication
экземпляр для тестовых случаев.
Мое AssetRepositoryImpl
заключается в следующем:
AssetRepositoryИмпл
@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?
Ответ №1:
Похоже, вам не хватает некоторых шагов в настройке кинжала, я включил контрольный список, который использую.
- Создание CustomTestRunner
class MyCustomTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, MyTestApplication::class.java.name, context)
}
}
- Добавить в бегун для тестирования в приложение/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()
}
}
Если вы ищете более подробную информацию о том, что делает каждый шаг, вы можете найти эту информацию здесь.