我正在根据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)
总是返回null
。
那么我怎样才能像谷歌一样实现相同的单元测试,但是在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 相同。
你是否已经使用过这个库,但我建议你使用带有 MVP 代码架构的 Dagger 2 库,通过改进你的依赖关系和耦合来简化你的单元测试
这种方法所做的只是showTask(task:Task(。因此,断言此方法是在观察者开始观察后调用的。你不应该关心节目任务一旦被调用就会做什么。如果使用 Rx,最好让你的方法接受观察模式的参数和返回值,以便更容易编写单元测试。