Android Mockito kotlin.UninitializedPropertyAccessException: свойство lateinit dataManager не инициализировано

Я постоянно получаю 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 не было инициализировано

5
0
4 125
2

Ответы 2

Где у вас метод DataManager@Provides? Dagger распознает конструктор @Inject внутри AppDataManager, но не может распознать его как интерфейс. Создайте модуль для Dagger, который является абстрактным и использует @Binds

https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f

спасибо за ответ Туби! Я обновил свой вопрос классом модуля. Глядя на аннотацию @Binds

Mykola 14.09.2018 17:49

Хорошо, тогда он у тебя уже есть. @Binds - это не что иное, как у вас в текущем модуле

Tuby 14.09.2018 17:50

Я не могу понять, как заменить @Inject lateinit var dataManager: DataManager в моем Presenter на фиктивный объект

Mykola 14.09.2018 18:13

Я бы переключился на инъекцию конструктора

Tuby 14.09.2018 18:14

тогда мне нужно будет внедрить Presenter в Activity, что я действительно не хочу делать

Mykola 14.09.2018 18:28

Я использую для некоторых сложных вещей, таких как расширение существующего компонента кинжала и добавление TestModules с имитацией объектов.

Tuby 14.09.2018 18:30

Вы не назначаете свой макет полю. Назначьте его в своем методе тестирования. Перед звонком в attachView()

createAccountPresenter.dataManager = mockDataManager

Я не думаю, что это поможет, я должен работать немного по-другому

Mykola 14.09.2018 17:53

Вы пробовали? Если вы хотите, чтобы DI работал в тестах, вам нужно будет создать тестовые модули с имитируемыми объектами, а также иметь TestApplication. Что вы можете сделать, так это создать отдельные конструкторы package private, которые принимают экземпляр DataManager. Вы можете использовать его только для тестов. Но это то же самое, что я предложил в своем ответе.

Rajitha Siriwardena 14.09.2018 19:44

Думаю, ты ошибаешься. Мне не нужны тестовые модули для такого теста!

Mykola 14.09.2018 20:39

Если вы хотите, чтобы кинжал вводил что-то, вы делаете. Но, пожалуйста, докажите мне, что я ошибаюсь. Не думай просто так. Мне было бы очень интересно узнать, найдете ли вы другой способ

Rajitha Siriwardena 15.09.2018 08:35

прости, Раджита, может быть, мы говорим о двух разных вещах. Мне не нужен кинжал для инъекций, мне нужно имитировать внедренные объекты Dagger с помощью Mockito, вот и все. На самом деле у меня он работал с инъекцией конструктора Presenter, но это не то, что мне действительно нужно.

Mykola 17.09.2018 16:02

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