在设计任何系统时,您须要保证操做的正确性,而且随着系统在其整个生命周期内进行修改,此质量不会消退。您将设计测试,理想状况下,测试应该是自动化的。现代软件由完全的单元测试支持,Rx代码应该没有什么不一样。ios
在单元测试中,咱们通常会预约义一些序列值来验证,可是对于异步代码呢?好比下面的代码git
Observable.interval(1, TimeUnit.SECONDS).take(5)github
这是一个须要5秒钟才能完成的序列。这意味着使用此序列的每一个测试都须要5秒或更长时间。若是您要运行数千个测试,这根本不方便。并发
上面的代码不只耗费时间,并且在等待时实际上浪费了全部的时间。若是您能够快进时钟,那么几乎能够当即评估该序列。您实际上没法快进系统的时钟,但您能够快进虚拟时钟。在Rx中,设计决定只经过调度程序使用时间。此决定容许您使用称为TestScheduler的虚拟化时间的调度程序替换。异步
TestScheduler的调度方式与咱们在[Scheduling and threading]一章中所见的调度程序相同(/Part 4 - Concurrency/1. Scheduling and threading.md))。它会安排当即或未来执行的操做。不一样之处在于时间被冻结,只能根据要求进行。咱们决定时间进展和多少。单元测试
顾名思义,advanceTimeTo将执行计划到特定时刻的全部操做。这包括在调度程序被快进时调度的动做,即由其余动做调度的动做。测试
输出:spa
咱们安排了3个任务:一个是当即执行,另外两个是未来执行。调度程序将按计划的时间顺序同步执行在该段时间内安排的全部任务。线程
advanceTimeTo容许您将时间设置为任何值,包括当前时间以前的值。此实现决策可能会在测试中没必要要地引入bug,所以在适用时最好使用下一个方法。设计
advanceTimeBy提早相对于当前时刻的时间。在其余方面,像advanceTimeTo同样。
输出:
triggerActions不提早时间。它只执行计划到目前为止执行的操做。
输出:
没有什么能阻止在同一时刻并发执行。当发生这种状况时,咱们会发生scheduling冲突。执行两个同时执行任务的顺序与调度它们的顺序相同。
输出:
涉及异步操做的Rx operators使用scheduler调度这些操做。若是您查看Observable中的全部运算符,您将看到此类运算符具备scheduler的重载。这是您能够为TestScheduler补充实时调度程序的方法。
下面是一个示例,咱们将测试Observable.interval的输出与咱们指望它发出的内容。
输出:
这对于测试小的Rx代码片断(例如自定义运算符)很是有用。一个完整的系统可能会单独使用schedulers,从而使咱们的虚拟时间失效。Lee Campbell建议使用咱们本身的提供商来抽象Rx的调度工厂(Schedulers)。在调试模式下,咱们的自定义调度程序工厂将使用TestScheduler替换全部调度程序,而后咱们将使用它来控制整个系统的时间。
在上面的测试中,咱们手动收集了发出的值,并将它们与咱们的预期进行了比较。这个过程在测试中很常见,Rx与TestSubscriber一块儿打包,这将为咱们作到这一点。其事件处理程序将收集收到的每一个通知,并使它们可供咱们检查。使用TestSubscriber,咱们以前的测试成为:
输出:
TestSubscriber收集的不只仅是值,而是经过如下方法露出它们:
这里有两件事须要注意。首先是getLastSeenThread方法。TestSubscriber检查什么线程被唤起而且记录最新的。例如,若是要验证GUI线程上是否执行了操做,那么这将很是有用。另外一个有趣的事情是,可能会有多个终止事件,这违背了咱们在本指南开头时定义序列的方式。这也是subscriber可以收集多个终止事件的缘由。
TestSubscriber为一些基本断言:
还有一种方法能够阻止执行,直到TestSubscriber订阅的observable终止。
若是observable未能按时完成,则等待超时将抛出异常。
原文:https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%204%20-%20Concurrency/2.%20Testing%20Rx.md