You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:44:25