RxJava 之 TestScheduler

作者: fengzhizi715 | 来源:发表于2017-10-19 13:51 被阅读583次

    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还是很有用处的,可以节省很多等待的时间。

    参考资料:

    1. http://blog.chengyunfeng.com/?p=979
    2. https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0

    相关文章

      网友评论

        本文标题:RxJava 之 TestScheduler

        本文链接:https://www.haomeiwen.com/subject/jgzbyxtx.html