Макет реактивного ранца ViewModel для модульных тестов с использованием Dagger2 (Robolectric)

Итак, я пытаюсь написать модульный тест для своей деятельности с использованием Robolectric, однако я понятия не имею, как предоставить издевательскую модель представления, видя, как мой виртуальный компьютер создается непосредственно в классе. Это связано с тем, что ViewModel с учетом жизненного цикла реактивного ранца требует создания экземпляра класса Provider. Итак, я, по сути, ввожу пользовательский провайдер, а затем использую его для создания своей ViewModel. Я просмотрел другие примеры, но все они кажутся чрезвычайно запутанными. Как мне этого добиться?

class ActivityEpisodeList : AppCompatActivity() {

        @Inject
        lateinit var vmFactory: ViewModelProvider.Factory

        private lateinit var vm: ActivityViewModel


        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_episode_list)

            MvvmDaggerApp.get(this).appComponent.inject(this)

            vm = ViewModelProviders.of(this, vmFactory)[ActivityViewModel::class.java]
    }
}

Вот как я создаю свою ViewModel:

@Module
abstract class ViewModelModule {

    @Binds
    internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(ActivityViewModel::class)
    internal abstract fun postListViewModel(viewModel: ActivityViewModel): ViewModel

}


@Singleton
class ViewModelFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)

Можете ли вы показать нам свой класс модульного тестирования?

Khoa Tran 28.02.2019 08:57

Я столкнулся с похожей проблемой. Проблема здесь в том, что активность знает, как она внедряется. Попробуйте заглянуть в Dagger Android, это позволит вам внедрять зависимости полей в ваши действия. Однако это потребует хорошего рефакторинга.

Sean Blahovici 06.09.2019 03:38

@SeanBlahovici В настоящее время я использую внедрение поля в приведенном выше примере. Или вы имели в виду какую-то инъекцию конструктора?

SpecialSnowflake 26.09.2019 13:04
9
3
2 088
1

Ответы 1

Вы должны внедрить тестовую модель представления из модуля, который appComponent использует для создания здесь зависимостей.

Не создавайте модель представления самостоятельно. Создайте 2 модуля для appComponent, один из которых предоставляет исходные зависимости, а другой — тестовые/фиктивные зависимости. Что-то вроде этого -

@Module
public AppModule {
      public ViewModel appViewModel() { // return original here}
}

  @Module
public TestAppModule extends AppModule {
      public ViewModel appViewModel() { // return test/mock here}
}

В вашем тесте, когда вы создаете свой AppComponent, проходите TestAppModule вместо AppModule, тогда вы получите издевательские зависимости.

Мой компонент инициализируется в классе Application (MvvmDaggerApp). Я не уверен, что ты имеешь в виду. Я не могу создать его в своем тестовом классе.

SpecialSnowflake 19.02.2019 11:56

Для модульных тестов вам нужно будет создать его в коде инициализации теста. Например, в каком-то методе с аннотацией @Setup в случае Mockito.

Vishal Arora 19.02.2019 11:58

appComponent все еще вызывается в onCreate моей активности. Я не понимаю, как я смогу предоставить другой компонент для своей деятельности. Не могли бы вы объяснить на примере кода?

SpecialSnowflake 19.02.2019 12:01

Немного опоздал на вечеринку, но я почти сошел с ума, решая ту же проблему. Вы должны создать другое приложение для целей тестирования, которое расширит ваше рабочее приложение. Там вы переопределяете создание компонента, чтобы вернуть TestComponent. И вишенка на торте - в ваших тестах вы добавляете аннотацию ко всему тестовому классу, например @Config(application = TestApplication::class). Надеюсь, это кому-нибудь поможет :)

Mikołaj Karwowski 18.09.2021 18:44

Другие вопросы по теме