RxSwift - Test operators

使用RxTest测试operators

RxTest是一个独立于RxSwift的库。所以使用需要单独倒入,可以使用pod进行安装,RxTest提供了许多有用的功能用于测试RxSwift的代码。比如:TestScheduler,它是一个虚拟的时间调度者(virtual time scheduler),能够让我们很好的控制线性时间操作符的测试( testing time-linear operations),而且包括next(_:_:), completed(_:_:), and error(_:_:)等方法,能够让我们在测试的具体时间添加事件到观察者序列(observables)。它也可以添加hot和cold观察者序列,跟RxSwift功能类似。

Hot and Cold Observables

Hot observables:
 • Use resources whether there are subscribers or not.
 • Produce elements whether there are subscribers or not.
 • Are primarily used with stateful types such as Variable.
 
 Cold observables:
 • Only consume resources upon subscription.
 • Only produce elements if there are subscribers.
 • Are primarily used for async operations such as networking.

基本概念

TestScheduler:大多数时候,我们将使用TestScheduler的两个方法,一个是createObserver,一个是createHotObservable。
createObserver: 允许你创建TestableObserver,它将记录每次发送给它的事件。
createHotObservable:创建hot observable,这里我们可以传递事件给它,在指定的调度者(scheduler)中。
initialClock:该方法用于创建一个新的调度者。调度者(Schedulers)用于派发工作到多个线程。调度者是观察者序(Observables)实现异步事件的核心。但是测试异步代码并不容易。TestScheduler派发它的工作到主线程(main thread)并且使用虚拟时间(virtual time)来记录当事件发生的时刻,在大多数情况下,我们将设置initialClock为0.

TestableObserver & TestableObservable
 当我们创建了测试调度者,我们就可以进一步工作了,根据调度者创建TestableObserver 和 TestableObservable。

Tests & the Driver unit
测试Driver可能比较棘手。因为Driver经常切换线程到主调度者(MainScheduler)进行工作。所以有时候,testScheduler并不能够捕获到事件,而且测试不能继续,但是RxCocoa为我们提供了一个很好的函数来处理这个问题, func driveOnScheduler(_ scheduler: SchedulerType, action: () -> ()),能够改变Driver的scheduler。

简单Demo

1: 首先新建一个工程,并勾选包括单元测试,如下:



2: 使用Cocoapods导入相应的库,如果不会使用,可以看我之前的文章,podfile文件如下:



3:打开.xcworkspace项目,command+B编译无错,然后开始定位TestDemoTests.swift文件





4: 导入RxSwiftRxTest,暂时去除testExample()和testPerformanceExample()两个方法,添加两个实例

import XCTest
import RxSwift
import RxTest
@testable import TestDemo

class TestDemoTests: XCTestCase {
    
    var scheduler: TestScheduler!  //scheduler是TestScheduler的实例,将被用于每一次测试
    var subscription: Disposable!  //subscription将持有你每次测试的订阅
    
    override func setUp() {
        super.setUp()
        //1
        scheduler = TestScheduler(initialClock: 0)
    }
    
    override func tearDown() {
        //2
        scheduler.scheduleAt(1000) {
            self.subscription.dispose()
        }
        super.tearDown()
    }
}
注意:setUp()方法在每次开始测试之前会被调用,这是单元测试的基本内容,想了解unit-test,可以看这里

1:使用TestScheduler的初始化方法创建scheduler实例,指定initialClock为0,这表示你想在测试的开始时测试scheduler
2:tearDown在每次测试完成后被调用。在该方法里面,你的调度者(scheduler)将处理测试订阅者在1000毫秒的时候。注意:我们所写的测试每次运行都会少于一秒,所以这里在1秒的时候处理测试的订阅者(test’s subscription)的安全的。

5: 现在开始,写几个简单例子。测试amb操作符。我们在组合操作符中学习了amb,对于两个或者多个观察者序列,仅仅只有最先发送消息的观察者序列才能被订阅者监听。并且之后只有该序列发送消息有效。

    //1:
    func testAmb() {
        //2:
        let observer = scheduler.createObserver(String.self)
        //3:
        let observableA = scheduler.createHotObservable([
            //4:
            next(100,"a)"),
            next(200,"b)"),
            next(300,"c)")
            ])
        //5:
        let observableB = scheduler.createHotObservable([
            next(90,"1)"),
            next(200,"2)"),
            next(300,"3)")
            ])
        //6:
        let ambObservable = observableA.amb(observableB)
        //7:
        scheduler.scheduleAt(0) {
            //8: 
            self.subscription = ambObservable.subscribe(observer)
        }
        //9:
        scheduler.start()
        //10:
        let results = observer.events.map {
            $0.value.element!
        }
        //11:
        XCTAssertEqual(results, ["1)","2)","3)"])  //ok
    }
分析:
1:跟使用XCTest一样,方法命令必须使用test开始,这里我们创建了一个测试函数,命令为testAmb
2:使用scheduler的createObserver方法创建一个观察者,指定类型为String.观察者将记录每一次接受事件的时间戳,除了不打印任何内容,其它像RxSwift中的操作符debug
3:创建一个可测试的观察者序列observableA
4: 使用next(_:_:)方法在指定的时间添加.next事件到observableA,第一个参数为添加时间,第二个参数为具体值。即在具体的时间发送该事件。对于需要发送值的就指定值,如果是向按钮点击是不需要发送值的,那么就为空,使用小圆括号()即可
5:创建另外一个可测试的观察者序列observableB,同样在指定时间添加.next事件到observableB
6:接下来使用amb操作符,ambObservable的类型时Observable<String>
7:接下来告诉调度者(scheduler)安排具体时间的动作
8:为观察者序列添加观察者,并且是在时间为0的时候开始订阅。返回的订阅者进行引用,这样在tearDown中进行释放处理
9:为了开始测试操作来验证结果,我们需要使用start方法,这里开始了虚拟时间的调度者,观察者(observer)将接受.next事件,事件是最初通过amb操作符之后得到的ambObservable中的时间和元素
10:现在可以收集和分析结果数据,这里使用map操作符来转换观察者事件到对应事件到元素值
11:现在,我们可以使用断言来比较实际的数据和预期的结果数据,测试结果是正确的,因为observableB中的事件将被发送,所以与预期结果一致。

6:测试filter操作符

 func testFilter() {
        //1
        let observer = scheduler.createObserver(Int.self)
        //2
        let observable = scheduler.createHotObservable([
            next(100, 1),
            next(200, 2),
            next(300, 3),
            next(400, 2),
            next(500, 1)
            ])
        //3
        let filterObservable = observable.filter {
            $0 < 3
        }
        //4
        scheduler.scheduleAt(0) {
            self.subscription = filterObservable.subscribe(observer)
        }
        //5
        scheduler.start()
        //6
        let results = observer.events.map {
            $0.value.element!
        }
        //7
        XCTAssertEqual(results, [1,2,2,1])
    }
分析:
1:创建一个观察者,指定观察者序列事件的元素类型为Int
2:创建一个观察者序列,并且添加元素,使用next方法
3:过滤原观察者序列得到过滤之后的观察者序列
4:在0秒时,开始订阅观察者序列,并且使用全局变量subscription引用
5:开始执行调度者(scheduler)
6:收集结果
7:判断结果与预期是否相符合,运行正确

参考:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值