Я постоянно получаю kotlin.UninitializedPropertyAccessException: lateinit property xxx has not been initialized в моем тесте Mockito. Но приложение работает нормально. Примечание: я не хочу, чтобы докладчик был активен. Заранее спасибо!
Вот моя активность:
class CreateAccountActivity : AppCompatActivity(), CreateAccountView {
private var presenter: CreateAccountPresenter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_account)
presenter = CreateAccountPresenter()
((application) as CariumApp).getDaggerComponent().inject(presenter!!)
presenter?.attachView(this)
}
А вот и мой ведущий:
class CreateAccountPresenter {
private var view: CreateAccountView? = null
@Inject
lateinit var dataManager: DataManager
fun attachView(view: CreateAccountView) {
this.view = view
dataManager.getServiceDocuments(true, object : GetServiceDocumentsListener {
// ...
})
}
Вот мой DataManager:
interface DataManager {
fun getServiceDocuments(latest: Boolean, listener: GetServiceDocumentsListener)
}
и AppDataManager:
Singleton
class AppDataManager @Inject constructor(context: Context) : DataManager {
// ...
}
и, наконец, мой тест не работает:
class CreateAccountPresenterTest {
val mockDataManager: DataManager = mock()
val mockCreateAccountView: CreateAccountView = mock()
private val createAccountPresenter = CreateAccountPresenter()
@Test
fun getServiceDocuments() {
doAnswer {
val args = it.arguments
(args[1] as GetServiceDocumentsListener).onError()
null
}.`when`(mockDataManager).getServiceDocuments(Mockito.anyBoolean(), anyOrNull())
createAccountPresenter.attachView(mockCreateAccountView)
verify(mockCreateAccountView).hideLoadingDialog()
}
}
файл gradle:
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.22.0'
testImplementation "org.mockito:mockito-inline:2.22.0"
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.0.0-RC1"
implementation 'com.google.dagger:dagger:2.16'
kapt 'com.google.dagger:dagger-compiler:2.16'
Мой класс модуля:
@Module
open class MyModule(private var context: Context) {
@Provides
open fun provideContext(): Context {
return context
}
@Provides
@Singleton
internal fun provideDataManager(appDataManager: AppDataManager): DataManager {
return appDataManager
}
}
Фактическая ошибка: kotlin.UninitializedPropertyAccessException: свойство lateinit dataManager не было инициализировано
Где у вас метод DataManager@Provides? Dagger распознает конструктор @Inject внутри AppDataManager, но не может распознать его как интерфейс. Создайте модуль для Dagger, который является абстрактным и использует @Binds
https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f
Хорошо, тогда он у тебя уже есть. @Binds - это не что иное, как у вас в текущем модуле
Я не могу понять, как заменить @Inject lateinit var dataManager: DataManager в моем Presenter на фиктивный объект
Я бы переключился на инъекцию конструктора
тогда мне нужно будет внедрить Presenter в Activity, что я действительно не хочу делать
Я использую для некоторых сложных вещей, таких как расширение существующего компонента кинжала и добавление TestModules с имитацией объектов.
Вы не назначаете свой макет полю. Назначьте его в своем методе тестирования. Перед звонком в attachView()
createAccountPresenter.dataManager = mockDataManager
Я не думаю, что это поможет, я должен работать немного по-другому
Вы пробовали? Если вы хотите, чтобы DI работал в тестах, вам нужно будет создать тестовые модули с имитируемыми объектами, а также иметь TestApplication. Что вы можете сделать, так это создать отдельные конструкторы package private, которые принимают экземпляр DataManager. Вы можете использовать его только для тестов. Но это то же самое, что я предложил в своем ответе.
Думаю, ты ошибаешься. Мне не нужны тестовые модули для такого теста!
Если вы хотите, чтобы кинжал вводил что-то, вы делаете. Но, пожалуйста, докажите мне, что я ошибаюсь. Не думай просто так. Мне было бы очень интересно узнать, найдете ли вы другой способ
прости, Раджита, может быть, мы говорим о двух разных вещах. Мне не нужен кинжал для инъекций, мне нужно имитировать внедренные объекты Dagger с помощью Mockito, вот и все. На самом деле у меня он работал с инъекцией конструктора Presenter, но это не то, что мне действительно нужно.
спасибо за ответ Туби! Я обновил свой вопрос классом модуля. Глядя на аннотацию @Binds