能否在方法被调用时完成单元测试?附测试代码及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
相关产品推荐
相关产品推荐

