Mockito在Observable方法中失效,Presenter测试仅通过Observable外代码
解决RxJava Presenter测试中Observable逻辑不执行的问题
嘿,看起来你遇到的是RxJava在Presenter测试里的典型异步问题——毕竟Observable里的逻辑是异步跑的,你的测试大概率是没等异步操作做完就急着断言结果了。结合你给的代码片段,我给你梳理几个核心解决思路:
替换真实调度器为TestScheduler
你的Presenter依赖了SchedulerProvider,测试时绝对不能用真实的IO/UI线程调度,得换成TestScheduler来手动控制异步代码的执行时机。举个例子:// 测试类里初始化TestScheduler val testScheduler = TestScheduler() val mockSchedulerProvider = object : SchedulerProvider { override fun io(): Scheduler = testScheduler override fun ui(): Scheduler = testScheduler // 其他调度方法比如computed也同理替换 } // 用这个mock的调度器初始化Presenter val presenter = CompManCodePresenter(mockApiBag, CompositeDisposable(), mockSchedulerProvider)这样所有RxJava操作都会在TestScheduler里排队,不会真的异步执行。当你需要触发Observable里的逻辑时,只要调用
testScheduler.triggerActions(),就能让所有待执行的任务同步跑完,再去做断言就没问题了。Mock网络请求依赖(ApiBag)
测试Presenter时绝对不能用真实的网络请求,得用Mockito这类框架把apiBag给mock掉,预设它的返回结果。比如:// Mock ApiBag实例 val mockApiBag = mock(ServiceModule.ApiBag::class.java) // 模拟网络请求返回成功的Observable whenever(mockApiBag.yourCompmanCodeApi(anyMap())).thenReturn(Observable.just(ValidCodeResponse())) // 如果要模拟错误场景,就返回error的Observable whenever(mockApiBag.yourCompmanCodeApi(anyMap())).thenReturn(Observable.error(ApiException("Invalid code")))这样Presenter调用网络请求时,会拿到你预设的结果,不会真的去发网络请求,测试才能稳定可控。
确保View和订阅都正确绑定
首先要把mock的View实例attach到Presenter上(假设你的BasePresenter有attachView方法),然后要保证Observable的订阅被正确添加到CompositeDisposable里,不然订阅可能不会生效:// Presenter里的正确写法示例 apiBag.yourCompmanCodeApi(request) .subscribeOn(scheduler.io()) .observeOn(scheduler.ui()) .subscribe({ response -> // 成功逻辑 view?.hideProgress() view?.onCodeValidated(response) }, { error -> // 错误逻辑 view?.hideProgress() view?.showCodeError(error.message) }) .let { disposable.add(it) } // 一定要把订阅加到CompositeDisposable里测试时还要记得在
@After方法里清理Disposable,避免内存泄漏:@After fun tearDown() { presenter.disposable.clear() }正确的测试断言流程
测试时要按这个流程来:attach View → 调用Presenter的方法 → 触发TestScheduler的任务 → 验证View的回调是否被调用。比如:@Test fun `validate valid compman code should trigger success callback`() { // 准备工作 val mockView = mock(CompManCodeView::class.java) presenter.attachView(mockView) // 执行测试方法 presenter.validateCompmanCode("VALID123") // 触发所有异步任务 testScheduler.triggerActions() // 断言View的方法是否被正确调用 verify(mockView).showProgress() verify(mockView).hideProgress() verify(mockView).onCodeValidated(any()) }
如果你的代码里还有其他细节问题,比如Observable没有正确发射事件,或者线程调度的顺序错了,也可能导致测试不通过。可以先按上面的步骤排查,一般都能解决这类异步测试的问题。
内容的提问来源于stack exchange,提问作者Tarcisio Wensing

