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

能否在方法被调用时完成单元测试?附测试代码及Presenter实现

解决Presenter异步方法的单元测试问题

看起来你是想验证ProfilePresenter的loadData()方法调用时,能正确触发showLoading()和loadDataSuccess(),但因为RxJava的异步特性,你的测试可能没等到loadDataSuccess()执行就结束了,导致验证失败。我来帮你调整测试代码,确保能正确测试这两个方法的调用:

核心问题分析

你的loadData()方法里用了RxJava发起异步请求,单元测试默认是同步执行的,测试代码会在subscribe里的loadDataSuccess()执行前就完成,所以verify断言会失败。我们需要把异步操作改成同步执行,同时mock掉依赖的UserService来模拟成功响应。

第一步:调整测试代码

我们需要引入RxJava的测试调度器TestScheduler,并mock相关依赖:

@RunWith(PowerMockRunner.class)
@PrepareForTest({RxUtil.class}) // 如果RxUtil是静态工具类,需要提前准备mock
public class PresenterTest {
    @Mock
    private ProfileContract.View view;
    @Mock
    private UserService userService; // Mock UserService,避免真实网络请求
    private ProfilePresenter presenter;
    private TestScheduler testScheduler;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        testScheduler = new TestScheduler();
        
        // 替换RxUtil中的调度器为TestScheduler,让异步操作同步执行
        PowerMockito.mockStatic(RxUtil.class);
        when(RxUtil.mapper()).thenReturn(
            ObservableTransformer.empty()
                .subscribeOn(testScheduler)
                .observeOn(testScheduler)
        );
        
        // 初始化Presenter,注入mock的View和UserService
        presenter = new ProfilePresenter(view, userService);
    }

    @Test
    public void onLoadDataClicked() {
        // 模拟UserService返回成功的响应
        UserResponse mockResponse = new UserResponse(); // 替换成你的实际Response类
        when(userService.user()).thenReturn(Observable.just(mockResponse));
        
        // 调用目标方法
        presenter.loadData();
        
        // 立即验证showLoading被调用
        verify(view, times(1)).showLoading();
        
        // 手动触发TestScheduler执行所有待处理的异步任务
        testScheduler.triggerActions();
        
        // 现在验证loadDataSuccess被调用
        verify(presenter, times(1)).loadDataSuccess();
    }
}

第二步:优化Presenter的可测试性

为了让测试更顺畅,建议把UserService通过构造函数注入,而不是在Presenter内部创建:

class ProfilePresenter(
    private val mView: ProfileContract.View,
    private val mUserService: UserService // 构造函数注入依赖
) : ProfileContract.Handler {
    override fun loadData() {
        mView.showLoading()
        mUserService.user()
            .compose(RxUtil.mapper())
            .subscribe({ response ->
                loadDataSuccess()
            }, { error ->
                // 错误处理逻辑
            })
    }
}

关键说明

  • TestScheduler的作用:它可以将RxJava的异步操作转为同步执行,通过triggerActions()手动触发所有待执行的任务,确保loadDataSuccess()在断言前已经执行。
  • Mock UserService:必须模拟userService.user()的返回值,避免依赖真实的网络或数据库操作,保证测试的独立性。
  • RxUtil的处理:如果RxUtil.mapper()使用了默认调度器(比如Schedulers.io()),需要用PowerMock替换成TestScheduler,否则异步操作还是会在后台线程运行,测试无法捕获。

这样调整后,你的测试就能正确验证showLoading()和loadDataSuccess()的调用情况了。

内容的提问来源于stack exchange,提问作者azsoftco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:49:59