RxJava 之 TestScheduler

简介: RxJava 之 TestScheduler

TestScheduler 是专门用于测试的调度器,跟其他调度器的区别是TestScheduler只有被调用了时间才会继续。TestScheduler是一种特殊的、非线程安全的调度器,用于测试一些不引入真实并发性、允许手动推进虚拟时间的调度器。


在 RxJava2.x 中,原先RxJava1.x的Schedulers.test()被去掉了,想要获得TestScheduler对象可以通过直接new TestScheduler()的方式来实现。


TestScheduler 所包含的方法并不多,下面罗列几个关键的方法。


advanceTimeTo



将调度器的时钟移动到某个特定时刻。


例如:


时钟移动到10毫秒。

scheduler.advanceTimeTo(10, TimeUnit.MILLISECONDS);


时钟移动到20毫秒。

scheduler.advanceTimeBy(20, TimeUnit.MILLISECONDS);


下面的列子展示了0秒、20秒、40秒会打印不同的结果。

TestScheduler scheduler = new TestScheduler();
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("immediate");
            }
        });
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("20s");
            }
        },20, TimeUnit.SECONDS);
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("40s");
            }
        },40, TimeUnit.SECONDS);
        scheduler.advanceTimeTo(1, TimeUnit.MILLISECONDS);
        System.out.println("virtual time: " + scheduler.now(TimeUnit.MILLISECONDS));
        scheduler.advanceTimeTo(20, TimeUnit.SECONDS);
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeTo(40, TimeUnit.SECONDS);
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));


执行结果:

immediate
virtual time: 1
20s
virtual time: 20
40s
virtual time: 40


我们可以看到使用advanceTimeTo之后,移动不同的时间点会打印不同的内容。


当然,advanceTimeTo()也可以传负数,表示回到过去的时间点。但是一般不推荐这种用法。


advanceTimeBy



将调度程序的时钟按指定的时间向前移动。


例如:


时钟移动了10毫秒。

scheduler.advanceTimeBy(10, TimeUnit.MILLISECONDS);


再次调用刚才的方法,时钟又会移动了10毫秒。此时,时钟移动也到20毫秒,这是一个

累加的过程。

scheduler.advanceTimeBy(10, TimeUnit.MILLISECONDS);


下面的例子使用了timer操作符,timer是按照指定时间延迟发送的操作符,timer()并不会按周期地执行。该例子展示了2秒后atomicLong会自动加1

TestScheduler scheduler = new TestScheduler();
        final AtomicLong atomicLong = new AtomicLong();
        Observable.timer(2, TimeUnit.SECONDS, scheduler).subscribe(new Consumer<Long>() {
            @Override
            public void accept(final Long value) throws Exception {
                atomicLong.incrementAndGet();
            }
        });
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(1, TimeUnit.SECONDS);
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(1, TimeUnit.SECONDS);
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));


执行结果:

atomicLong's value=0, virtual time:0
atomicLong's value=0, virtual time:1
atomicLong's value=1, virtual time:2


这个结果符合预期,最初atomicLong为0,时钟移动到1秒它的值仍然为0,时钟再移动1秒相当于时钟移动到2秒,所以它的值变为1。


当然,advanceTimeBy()也可以传负数,表示回到过去。

TestScheduler scheduler = new TestScheduler();
        final AtomicLong atomicLong = new AtomicLong();
        Observable.timer(2, TimeUnit.SECONDS, scheduler).subscribe(new Consumer<Long>() {
            @Override
            public void accept(final Long value) throws Exception {
                atomicLong.incrementAndGet();
            }
        });
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(1, TimeUnit.SECONDS);
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(-1, TimeUnit.SECONDS);
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(2, TimeUnit.SECONDS);
        System.out.println("atomicLong's value="+atomicLong.get() + ", virtual time:" + scheduler.now(TimeUnit.SECONDS));


执行结果:

atomicLong's value=0, virtual time:0
atomicLong's value=0, virtual time:1
atomicLong's value=0, virtual time:0
atomicLong's value=1, virtual time:2


triggerActions



triggerActions不会修改时间,它执行任何计划中的但是未启动的任务,已经执行过的任务不会再启动。

TestScheduler scheduler = new TestScheduler();
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("immediate");
            }
        });
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("20s");
            }
        },20, TimeUnit.SECONDS);
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));


执行结果:

virtual time: 0


稍微改一下代码,增加scheduler.triggerActions()

TestScheduler scheduler = new TestScheduler();
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("immediate");
            }
        });
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("20s");
            }
        },20, TimeUnit.SECONDS);
        scheduler.triggerActions();
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));


执行结果:

immediate
virtual time: 0


此时由于执行了triggerActions(),所以打印了immediate。


再改一下,增加advanceTimeBy()

TestScheduler scheduler = new TestScheduler();
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("immediate");
            }
        });
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("20s");
            }
        },20, TimeUnit.SECONDS);
        scheduler.triggerActions();
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(20,TimeUnit.SECONDS);


执行结果:

immediate
virtual time: 0
20s


如果将triggerActions()放在最后,看看效果

TestScheduler scheduler = new TestScheduler();
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("immediate");
            }
        });
        scheduler.createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("20s");
            }
        },20, TimeUnit.SECONDS);
        System.out.println("virtual time: " + scheduler.now(TimeUnit.SECONDS));
        scheduler.advanceTimeBy(20,TimeUnit.SECONDS);
        scheduler.triggerActions();


执行结果:

virtual time: 0
immediate
20s


因为已经使用了advanceTimeBy(),所以即使再调用triggerActions()也不会执行已经启动过的任务。


总结



对于测试一些需要精确时间的任务,TestScheduler还是很有用处的,可以节省很多等待的时间。

相关文章
|
6天前
|
监控 Java 调度
Spring中的任务调度:探索@Scheduled和@Schedules注解的威力
Spring中的任务调度:探索@Scheduled和@Schedules注解的威力
42 0
|
6天前
|
存储 NoSQL Java
APScheduler简介
APScheduler简介
35 0
|
6天前
|
调度
APScheduler任务相关操作
APScheduler任务相关操作
20 0
|
6天前
|
前端开发 安全 调度
React 之 Scheduler 源码解读(下)
本篇我们接着《React 之 Scheduler 源码解读(上)》,讲解延时任务的执行源码。
42 0
|
6天前
|
前端开发 JavaScript API
React 之 Scheduler 源码解读(上)
React 之 Scheduler 源码解读(上)
56 0
|
6天前
|
前端开发 调度
300 行代码实现 React 的调度器 Scheduler
说是实现,但其实我们只是在 React Scheduler 源码的基础上进行了简化,省略掉一些繁琐的细节,添加了丰富的注释,保证代码可直接执行。 大家可以复制代码到编辑器中,直接运行,非常适合学习 React 源码用。
43 0
|
6天前
|
存储 JavaScript 前端开发
RxJS中的调度器(Scheduler)机制
RxJS中的调度器(Scheduler)机制
57 0
|
8月前
|
调度
RxSwift调度器 - Schedulers
RxSwift调度器 - Schedulers
64 1