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

JUnit测试异常类型校验问题:RxJava链式调用测试失败求助

解决RxJava单元测试捕获自定义异常失败的问题

首先,你的测试用例失败主要有两个核心原因:

1. 未正确Mock依赖的行为

你直接调用了mService.updateData,但没有预先配置mApiProvider.updateData()的Mock逻辑——它根本不会抛出你预期的RecordNotFoundException,自然触发不了测试的异常断言。

2. RxJava的blockingGet()会包装原始异常

就算mApiProvider真的抛出了异常,RxJava的blockingGet()方法在处理错误信号时,会把原始异常包装进一个RuntimeException(比如OnErrorNotImplementedException)里抛出,而非直接抛出你的自定义异常。所以@Test(expected = RecordNotFound.class)根本匹配不到实际抛出的异常类型。

正确的测试方案(推荐用RxJava官方测试工具)

使用TestObserver订阅Single是RxJava测试的标准做法,它能直接验证错误信号的类型:

@Test
public void updateData_recordNotFound() {
    // 第一步:Mock mApiProvider,让它调用时抛出目标异常
    when(mApiProvider.updateData(any(Object.class))).thenThrow(new RecordNotFoundException());

    // 第二步:调用方法并获取TestObserver
    TestObserver<Object> testObserver = mService.updateData(new Object()).test();

    // 第三步:验证错误类型是否符合预期
    testObserver.assertError(RecordNotFoundException.class);
}

若坚持使用blockingGet()的替代方案

如果一定要用blockingGet(),可以捕获包装后的RuntimeException,再检查它的根源是否是你的自定义异常:

@Test
public void updateData_recordNotFound() {
    // 先配置Mock依赖的行为
    when(mApiProvider.updateData(any(Object.class))).thenThrow(new RecordNotFoundException());

    try {
        mService.updateData(new Object()).blockingGet();
        // 如果走到这里,说明未抛出异常,测试失败
        fail("Expected RecordNotFoundException to be thrown");
    } catch (RuntimeException e) {
        // 检查异常的根源是否为目标自定义异常
        assertTrue("Exception cause should be RecordNotFoundException", 
                   e.getCause() instanceof RecordNotFoundException);
    }
}

额外小优化:简化RxJava业务代码

你原来的Single.defer加手动try-catch可以用Single.fromCallable替代,它会自动捕获Callable中的异常并转为Single的error信号,代码更简洁:

public Single<Object> updateData(Object object){
    return Single.fromCallable(() -> mApiProvider.updateData(object));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:06:04