【问题标题】:TestScheduler not working while testing specific usecaseTestScheduler 在测试特定用例时不起作用
【发布时间】:2018-03-19 07:55:33
【问题描述】:

我正在测试单个用例。但是测试观察者不会在测试环境中发出任何东西。

  • 即使我将 subscribeOn()Schedulers.newThread() 更改为 TestScheduler() 仍然测试失败。我很困惑。我不知道是什么 我在这里做错了吗?
  • 如果我删除subscribeOn,observeOn 方法然后测试成功。然后 TestScheduler() 的实际用途是什么?

以下是UseCase.kt 文件

abstract class UseCase<T>(val postExecutionThread: PostExecutionThread) {

    abstract fun buildUseCaseBuilder(): Observable<T>

    /**
     * execute method for observables
     */
    open fun execute(): Observable<T> {
        return buildUseCaseBuilder()
                .subscribeOn(Schedulers.newThread())
                .observeOn(postExecutionThread.getScheduler())
    }
}

用上面的被测类跟随测试类

class UseCaseTest {

    val postExecutionThread=Mockito.mock(PostExecutionThread::class.java)
    val result: String="test"
    val testObserver=TestObserver<String>()

    @Before
    fun setUp() {
        _when(postExecutionThread.getScheduler()).thenReturn(TestScheduler())
    }

    @Test
    fun `test execute method of use case`() {
        println(" thread type ${postExecutionThread.getScheduler()}")

        //test fail
        //java.lang.AssertionError: Value count differs; Expected: 1 [test], Actual: 0 [] (latch = 1, values = 0, errors = 0, completions = 0)
        TestUseCase(postExecutionThread).execute().test()
                .assertResult(result)

        //subscriber not print any thing
        TestUseCase(postExecutionThread).execute().subscribe{
            println("called $it")
        }
    }

    inner class TestUseCase(postExecutionThread: PostExecutionThread?) : UseCase<String>(postExecutionThread!!) {
        override fun buildUseCaseBuilder(): Observable<String> {
            return Observable.just(result)
        }
    }
}

【问题讨论】:

    标签: android testing junit kotlin rx-java2


    【解决方案1】:

    问题是,您的测试是在一个线程上运行的,而不是您使用subscribeOn()observeOn() 指定的线程。无论subscribeOn()/observeOn() 中指定了什么,您想要的是让测试和被测代码在同一个线程上同步运行。

    您可以使用自定义 @Rule 来实现这一点,例如 this one

    /**
     * This rule registers Handlers for RxJava and RxAndroid to ensure that subscriptions
     * always subscribeOn and observeOn Schedulers.trampoline().
     * Warning, this rule will reset RxAndroidPlugins and RxJavaPlugins before and after each test so
     * if the application code uses RxJava plugins this may affect the behaviour of the testing method.
     */
    public class RxSchedulersOverrideRule implements TestRule {
    
        private final Function<Callable<Scheduler>, Scheduler> mRxAndroidSchedulersHook =
                new Function<Callable<Scheduler>, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable<Scheduler> schedulerCallable)
                            throws Exception {
                        return getScheduler();
                    }
                };
    
        private final Function<Scheduler, Scheduler> mRxJavaImmediateScheduler =
                new Function<Scheduler, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Scheduler scheduler) throws Exception {
                        return getScheduler();
                    }
                };
    
        @Override
        public Statement apply(final Statement base, Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    RxAndroidPlugins.reset();
                    RxAndroidPlugins.setInitMainThreadSchedulerHandler(mRxAndroidSchedulersHook);
    
                    RxJavaPlugins.reset();
                    RxJavaPlugins.setIoSchedulerHandler(mRxJavaImmediateScheduler);
                    RxJavaPlugins.setNewThreadSchedulerHandler(mRxJavaImmediateScheduler);
    
                    base.evaluate();
    
                    RxAndroidPlugins.reset();
                    RxJavaPlugins.reset();
                }
            };
        }
    
        public Scheduler getScheduler() {
            return Schedulers.trampoline();
        }
    
    }
    

    使用此代码,您可以拦截所有调度程序并使所有内容都在 trampoline() 调度程序上运行。

    现在只需将以下@Rule 添加到您的测试中:

    public class MyTestClass { @Rule public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule(); @Test public void someTest() { ... } }

    【讨论】:

    • 是的,你是对的,我只是添加了 trampoline() 并测试works.thanks。那么 TestScheduler 的实际用途是什么?
    • TestScheduler 当您想要提前时间时会派上用场,例如您有一个流,它将在 10 秒内发出一个值。您不想在测试中等待 10 秒,而是希望提前 10 秒并验证该值是否已发出。请参阅 this 博客文章以获取示例用例。
    • 谢谢我明白了。我正在用蹦床注入 subscribeOn 和 observeOn。我不会在我的域层中添加 RxAndroidPlugins 依赖项,非常感谢。感谢您的帮助。
    • 你拯救了我的一天。我也通过了trampoline() 并且工作了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 2019-04-27
    相关资源
    最近更新 更多