我创建了一个Observable,它通过从onNext
调用DispatchQueue.async
来发出事件,并且即使我使用了{ sleep(...)
。
我创建以下TestScheduler
,它从gRPC流中读取事件。我相信gRPC在这里并不是那么重要:只需注意我在Observable
循环中call.receive()
,并将其提供给while
。
onNext
我现在尝试使用以下功能测试此代码。同样,第一段仅涉及设置gRPC上下文。我认为重要的是:
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)
}
TestScheduler
传递给scheduler
,并用作上面的Telemetry
)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(...)
不会收到任何事件。感觉是断言发生在事件发出之前。
我应该如何处理?
答案 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()
}