能否用Mockito验证RxJava 2中Observable的实际执行逻辑?
如何用Mockito验证RxJava Observable/Completable的实际执行
你碰到的这个问题其实很典型——Mockito默认只能验证方法是否被调用,但没法直接验证RxJava流里的逻辑是否真的被执行了。咱们先拆解下问题根源,再给出解决方案。
问题根源分析
你当前的测试里,verify(bar, times(1)).method3()通过了,是因为andThen操作符的特性:它会先调用bar.method3()来获取Completable实例,哪怕前面的method2()返回错误,这个方法调用还是会发生。但生产环境里,由于method2抛出了错误,andThen后面的Completable根本不会被订阅执行,所以method3里的打印逻辑永远跑不起来。
简单说:Mockito验证的是「bar.method3()被调用过」,但你真正想验证的是「method3返回的Completable的逻辑被执行过」——这俩完全是两回事。
解决方案:追踪Completable的订阅执行
要验证RxJava流的实际执行,我们需要给mock的Completable加个「执行标记」,来确认它的逻辑是否真的被触发了。这里用Mockito的Answer就能轻松实现:
修改后的测试代码
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import io.reactivex.Completable; import java.util.concurrent.atomic.AtomicBoolean; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class FooTest { @Mock private Bar bar; @InjectMocks private Foo foo; @Test public void testExecuteAbortsAfterMethod2Error() throws Exception { // 模拟method1正常完成 when(bar.method1()).thenReturn(Completable.complete()); // 模拟method2抛出错误 when(bar.method2()).thenReturn(Completable.error(new Exception())); // 用原子布尔值追踪method3的逻辑是否被执行 AtomicBoolean method3LogicExecuted = new AtomicBoolean(false); // 当调用bar.method3()时,返回一个带追踪逻辑的Completable when(bar.method3()).thenAnswer(invocation -> Completable.fromAction(() -> { // 这里就是method3原本的逻辑,我们加个标记 method3LogicExecuted.set(true); // 如果需要模拟原逻辑,也可以在这里调用实际的打印等操作 // System.out.println("method 3"); }) ); // 执行测试并断言错误 foo.execute() .test() .assertError(Exception.class); // 验证方法调用情况(method1、method2各调用1次,method3确实被调用了) verify(bar, times(1)).method1(); verify(bar, times(1)).method2(); verify(bar, times(1)).method3(); // 关键验证:method3的实际逻辑没有被执行 assertThat(method3LogicExecuted.get()).isFalse(); } }
代码解释
- 原子布尔值追踪执行状态:用
AtomicBoolean来记录method3的Completable逻辑是否被触发,它是线程安全的,适合测试场景。 - 用Answer自定义Completable:通过
thenAnswer返回一个自定义的Completable,当这个Completable被订阅执行时,会把标记设为true。 - 双重验证:既验证了
bar.method3()被调用过(符合代码逻辑),又验证了它的实际执行逻辑没有被触发(符合生产环境的行为)。
额外提示
如果你的RxJava流更复杂(比如涉及线程调度),还可以结合TestScheduler来控制流的执行时机,但对于你当前的场景,上面的方案已经足够解决问题了。
内容的提问来源于stack exchange,提问作者Lau
相关产品推荐
相关产品推荐

