Макет юнит-тестирования для RxJava - PullRequest
2 голосов
/ 01 июня 2019

Я пишу модульные тесты на основе примеров Google: TaskDetailPresenterTest.kt # L102

Они используют ArgumentCaptor<TasksDataSource.GetTaskCallback> для вызова обратного вызова с поддельными данными COMPLETED_TASK

@Test 
fun getCompletedTaskFromRepositoryAndLoadIntoView() {
    presenter = TaskDetailPresenter(COMPLETED_TASK.id, tasksRepository, taskDetailView)
    presenter.start()

    // Then task is loaded from model, callback is captured
    verify(tasksRepository).getTask(
                eq(COMPLETED_TASK.id), capture(taskCallbackCaptor))

    // When task is finally loaded
    taskCallbackCaptor.value.onTaskLoaded(COMPLETED_TASK) // Trigger callback
}

Все работает нормально, потому что они используют TasksDataSource.GetTaskCallback для возврата данных. См .: TaskDetailPresenter.kt # L36 :

fun getTask(taskId: String, callback: GetTaskCallback)

Тогда используйте как

tasksRepository.getTask(taskId, object : TasksDataSource.GetTaskCallback {
    override fun onTaskLoaded(task: Task) {
        showTask(task)
    }
}

Но когда я пытаюсь использовать RxJava Single <> вместо обычного обратного вызова , например:

fun getTask(taskId: String): Single<Task>

Затем используйте как

tasksRepository.getTask(taskId)
    .subscribe(object : SingleObserver<Task> {
        override fun onSuccess(task: Task) {
            showTask(task)
        }

        override fun onError(e: Throwable) {
        }
    })
}

Тогда я не могу использовать ArgumentCaptor<>, чтобы вызвать возврат поддельных данных. При выполнении теста всегда выдается NullPointerException, потому что tasksRepository.getTask(taskId) равно всегда return null.

Так как мне выполнить тот же модульный тест, что и в Google, но в RxJava?


Код моего модульного теста:

@Mock private lateinit var tasksRepository: TasksRepository

@Captor private lateinit var taskCaptor: ArgumentCaptor<SingleObserver<Task>>

private lateinit var presenter: TaskDetailPresenter

@Before fun setup() {
    MockitoAnnotations.initMocks(this)
}

@Test 
fun getCompletedTaskFromRepositoryAndLoadIntoView() {
    presenter = TaskDetailPresenter(COMPLETED_TASK.id, tasksRepository, taskDetailView)
    presenter.start()

    // Then task is loaded from model, callback is captured
    verify(tasksRepository).getTask(
                eq(COMPLETED_TASK.id)).subscribe(taskCaptor.capture())

    // When task is finally loaded
    taskCaptor.value.onSuccess(COMPLETED_TASK) // Trigger callback
}

Обратите внимание, что все остальные части (декларация, настройка, насмешка, ...) такие же, как Google.

Ответы [ 2 ]

0 голосов
/ 02 июня 2019

Все, что делает этот метод - это showTask (task: Task).Поэтому утверждайте, что этот метод вызывается после того, как ваш наблюдатель начинает наблюдать.Вам не важно, что будет делать showTask после того, как он будет вызван.Если вы используете Rx, гораздо лучше заставить ваши методы принимать аргументы и возвращать значение шаблона наблюдения, чтобы упростить написание модульного теста.

0 голосов
/ 01 июня 2019

Я не знаю, использовали ли вы уже эту библиотеку, но я бы посоветовал вам использовать библиотеку Dagger 2 с архитектурой кода MVP, чтобы упростить ваши модульные тесты за счет улучшения ваших зависимостей и связей

...