测试时覆写RxAndroid调度器:ThreadExecutor的SubscribeOn问题
你已经搞定了observeOn的调度器替换,那subscribeOn这边的问题核心是处理Schedulers.from(threadExecutor)生成的Scheduler。我给你分享两种可行的方案,都是围绕让这个Scheduler同步执行任务来实现的:
方案一:Mock ThreadExecutor实现同步执行
假设你的ThreadExecutor是继承自Executor的接口(和那个Android Clean Architecture仓库的定义一致),我们可以通过Mock它的execute方法,让传入的Runnable直接在当前测试线程执行:
// 1. 定义一个直接在当前线程执行任务的Executor val immediateExecutor = Executor { runnable -> runnable.run() } // 2. Mock ThreadExecutor实例 val mockThreadExecutor: ThreadExecutor = mock() // 3. 让mock的execute方法使用我们的同步执行逻辑 whenever(mockThreadExecutor.execute(any())).thenAnswer { invocation -> val runnable = invocation.getArgument<Runnable>(0) immediateExecutor.execute(runnable) } // 4. 将这个mock的ThreadExecutor传入你的UseCase val useCase = UseCase(testRepo, mockThreadExecutor, testPostExecutionThread)
这样处理后,Schedulers.from(threadExecutor)生成的Scheduler会直接在测试线程同步执行任务,完全符合测试需求,和你替换observeOn调度器的思路保持一致。
方案二:直接使用自定义的同步ThreadExecutor实现
如果你的ThreadExecutor有具体的实现类(比如仓库里的JobExecutor),且允许传入Executor作为构造参数,那你可以直接创建一个同步执行的实例,不需要Mock:
val immediateExecutor = Executor { runnable -> runnable.run() } val testThreadExecutor = JobExecutor(immediateExecutor) // 假设JobExecutor是你的ThreadExecutor实现类 val useCase = UseCase(testRepo, testThreadExecutor, testPostExecutionThread)
这种方式更直接,适合你不想引入Mock的场景。
为什么这两种方案有效?
Schedulers.from(executor)创建的Scheduler,本质上是把RxJava的任务委托给传入的Executor执行。只要我们让这个Executor的execute方法同步运行Runnable,就相当于把subscribeOn的调度器替换成了同步类型(比如Schedulers.trampoline()或者Schedulers.immediate()),整个UseCase的数据流都会在测试线程按顺序执行,方便你做结果断言。
内容的提问来源于stack exchange,提问作者Chan Myae Aung

