需要睡觉才能让TestScheduler完成

时间:2019-01-28 08:57:32

标签: rx-swift

摘要

我创建了一个Observable,它通过从onNext调用DispatchQueue.async来发出事件,并且即使我使用了{ sleep(...)

详细问题

我创建以下TestScheduler,它从gRPC流中读取事件。我相信gRPC在这里并不是那么重要:只需注意我在Observable循环中call.receive(),并将其提供给while

onNext

我现在尝试使用以下功能测试此代码。同样,第一段仅涉及设置gRPC上下文。我认为重要的是:

  1. 我使用private func createPositionObservable() -> Observable<Position> { return Observable.create { observer in let request = DronecodeSdk_Rpc_Telemetry_SubscribePositionRequest() do { let call = try self.service.subscribePosition(request, completion: { (callResult) in if callResult.statusCode == .ok || callResult.statusCode == .cancelled { observer.onCompleted() } else { observer.onError(RuntimeTelemetryError(callResult.statusMessage!)) } }) DispatchQueue.init(label: "DronecodePositionReceiver").async { while let responseOptional = try? call.receive(), let response = responseOptional { observer.onNext(Position.translateFromRpc(response.position)) } } return Disposables.create { call.cancel() } } catch { observer.onError(error) return Disposables.create() } } .subscribeOn(scheduler) }
  2. 我将此调度程序传递给gRPC(TestScheduler传递给scheduler,并用作上面的Telemetry
  3. 我在断言之前subscribeOn(scheduler)
sleep(2)

如果我不func checkPositionObservableReceivesEvents(positions: [DronecodeSdk_Rpc_Telemetry_Position]) { let fakeService = DronecodeSdk_Rpc_Telemetry_TelemetryServiceServiceTestStub() let fakeCall = DronecodeSdk_Rpc_Telemetry_TelemetryServiceSubscribePositionCallTestStub() fakeCall.outputs.append(contentsOf: positions.map{ position in createPositionResponse(position: position) }) fakeService.subscribePositionCalls.append(fakeCall) let expectedEvents = positions.map{ position in next(1, translateRPCPosition(positionRPC: position)) } let scheduler = TestScheduler(initialClock: 0) let observer = scheduler.createObserver(Telemetry.Position.self) let telemetry = Telemetry(service: fakeService, scheduler: scheduler) let _ = telemetry.position.subscribe(observer) scheduler.start() sleep(2) XCTAssertEqual(expectedEvents.count, observer.events.count) XCTAssertTrue(observer.events.elementsEqual(expectedEvents, by: { (observed, expected) in observed.value == expected.value })) } ,则我的断言将失败并且sleep(...)不会收到任何事件。感觉是断言发生在事件发出之前。

我应该如何处理?

1 个答案:

答案 0 :(得分:1)

您可以通过不在create函数内部创建DispatchQueue来解决此问题。相反,该函数需要接受Scheduler作为参数,然后使用该Scheduler创建异步块。

然后在您的测试中,通过测试计划程序。

类似的事情可以做到:

let disposable = self.scheduler.schedule(0, action: { _ in
    var cancel = false
    while let responseOptional = try? call.receive(), let response = responseOptional, cancel == false {
        observer.onNext(Position.translateFromRpc(response.position))
    }
    return Disposables.create { cancel = true }
})

return Disposables.create {
    disposable.dispose()
    call.cancel()
}