RxSwift/RxTest 如何使用 Observable 测试异步函数 return
RxSwift/RxTest How to test async function with Observable return
我是 RxSwift 的新手,我正在尝试创建一些单元测试。在这种情况下,我想测试从实时数据库 Firebase 获取对象是否正确。
func getAllPosts() -> Observable<[PostItem]> {
ref = Database.database().reference()
return Observable.create { observer -> Disposable in
self.ref.child("Posts").observe(.value) { (snapshot) in
var postsList:[PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
observer.onNext(postsList)
}
return Disposables.create {}
}
}
问题是 firebase 的 return 是异步的,我尝试测试的方式在 return.
之前完成
func testFetchPosts() throws {
let newsAPIService = NewsAPIService()
let posts = newsAPIService.fetchNewsFromAPI()
XCTAssertNil(posts, "The posts is nil")
}
Obs:我尝试使用 XCTest 期望,但我不知道是否实施不正确或者它是否真的不起作用
谢谢!
我建议您将逻辑移出 Observable.create 以便您可以独立测试它。像这样:
func getAllPosts() -> Observable<[PostItem]> {
return Observable.create { observer in
// note that you don't have to store this value. The disposable will hold it for you.
let ref = Database.database().reference()
// the `handleSnapshot(observer:)` function is defined below.
ref.child("Posts").observe(.value, handleSnapshot(observer: observer))
// make sure you turn off the observation on dispose.
return Disposables.create { ref.stop() }
}
}
您的逻辑应该在一个单独的高阶函数中:
// note that this is a free function. It should not be defined inside any class or struct.
// I'm guessing on the `Snapshot` type. I don't use Firebase.
func handleSnapshot(observer: AnyObserver<[PostItem]>) -> (Snapshot) -> Void {
{ snapshot in
var postsList: [PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
observer.onNext(postsList)
}
}
测试此功能很容易:
func testShapshotHandler() throws {
let scheduler = TestScheduler(initialClock: 0)
let observer = scheduler.createObserver([PostItem].self)
let snapshot = Snapshot(children: [Child()]) // create a snapshot object here
let sut = handleSnapshot(observer: observer.asObserver())
sut(snapshot)
// assumes `PostItem` is Equatable
XCTAssertEqual(observer.events, [.next(0, [PostItem(id: "", authorId: "", name: "", content: "", createAt: "")])])
}
如果你对高阶函数感到不舒服,你可以这样做:
func getAllPosts() -> Observable<[PostItem]> {
return Observable.create { observer in
let ref = Database.database().reference()
ref.child("Posts").observe(.value) { snapshot in
observer.onNext(handle(snapshot: snapshot))
}
return Disposables.create { ref.stop() }
}
}
func handle(snapshot: Snapshot) -> [PostItem] {
var postsList: [PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
return postsList
}
现在测试逻辑更容易了。您不再需要测试调度程序或观察器。
我是 RxSwift 的新手,我正在尝试创建一些单元测试。在这种情况下,我想测试从实时数据库 Firebase 获取对象是否正确。
func getAllPosts() -> Observable<[PostItem]> {
ref = Database.database().reference()
return Observable.create { observer -> Disposable in
self.ref.child("Posts").observe(.value) { (snapshot) in
var postsList:[PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
observer.onNext(postsList)
}
return Disposables.create {}
}
}
问题是 firebase 的 return 是异步的,我尝试测试的方式在 return.
之前完成func testFetchPosts() throws {
let newsAPIService = NewsAPIService()
let posts = newsAPIService.fetchNewsFromAPI()
XCTAssertNil(posts, "The posts is nil")
}
Obs:我尝试使用 XCTest 期望,但我不知道是否实施不正确或者它是否真的不起作用
谢谢!
我建议您将逻辑移出 Observable.create 以便您可以独立测试它。像这样:
func getAllPosts() -> Observable<[PostItem]> {
return Observable.create { observer in
// note that you don't have to store this value. The disposable will hold it for you.
let ref = Database.database().reference()
// the `handleSnapshot(observer:)` function is defined below.
ref.child("Posts").observe(.value, handleSnapshot(observer: observer))
// make sure you turn off the observation on dispose.
return Disposables.create { ref.stop() }
}
}
您的逻辑应该在一个单独的高阶函数中:
// note that this is a free function. It should not be defined inside any class or struct.
// I'm guessing on the `Snapshot` type. I don't use Firebase.
func handleSnapshot(observer: AnyObserver<[PostItem]>) -> (Snapshot) -> Void {
{ snapshot in
var postsList: [PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
observer.onNext(postsList)
}
}
测试此功能很容易:
func testShapshotHandler() throws {
let scheduler = TestScheduler(initialClock: 0)
let observer = scheduler.createObserver([PostItem].self)
let snapshot = Snapshot(children: [Child()]) // create a snapshot object here
let sut = handleSnapshot(observer: observer.asObserver())
sut(snapshot)
// assumes `PostItem` is Equatable
XCTAssertEqual(observer.events, [.next(0, [PostItem(id: "", authorId: "", name: "", content: "", createAt: "")])])
}
如果你对高阶函数感到不舒服,你可以这样做:
func getAllPosts() -> Observable<[PostItem]> {
return Observable.create { observer in
let ref = Database.database().reference()
ref.child("Posts").observe(.value) { snapshot in
observer.onNext(handle(snapshot: snapshot))
}
return Disposables.create { ref.stop() }
}
}
func handle(snapshot: Snapshot) -> [PostItem] {
var postsList: [PostItem] = []
for child in snapshot.children {
let snap = child as! DataSnapshot
let postDict = snap.value as! [String: Any]
let postAux = PostItem(id: snap.ref.key ?? "", authorId: postDict["authorId"] as? String ?? "", name: postDict["name"] as? String ?? "", content: postDict["content"] as? String ?? "", createAt: postDict["createAt"] as? String ?? "")
postsList.append(postAux)
}
return postsList
}
现在测试逻辑更容易了。您不再需要测试调度程序或观察器。