问题描述
我有一个演示项目来获取远程照片数据,当用户点击收藏夹按钮时,它会在本地数据库中记录照片。
抱歉我的英语不好...
问题:
当我尝试使用 RxTest 期待 Resultviewmodel。sectionOfCells
结果有时会是 1 或 2 或 3。像图像:
为什么结果计数不是 4,因为我给了 trigger
4 个 Recorded 事件。
项目构建运行良好,并且在 ResultViewController 上正确执行操作(viewWillAppear 触发获取,点击收藏夹以保存在数据库中)。
该项目可以下载here。分支地址:test/Resultviewmodel
这是我的 Resultviewmodel transform(input:) -> Output:
// at Resultviewmodel.swift
func transform(input: ResultInput) -> ResultOutput {
let onSavedTriggerReload = PublishSubject<Bool>()
let reloadData: Observable<Bool> = Observable.of(
input.triggerFetch.asObservable().map { true },onSavedTriggerReload.debug("\n\n======= On saved or remove trigger >> \n\n")
)
.merge()
.share()
let tappedShare = input.photoSelected.share()
let favor = reloadData
.flatMap { [weak self] _ in self?.fetchFavoriteCase() ?? .just([:]) }
.debug("\n\n======= favorites ====== >>\n\n")
let response = reloadData
.flatMap { [weak self] _ in self?.searchRemoteCase() ?? .empty() }
.debug("\n\n======= search remote ====== >> \n\n")
let sectionOfCells = Observable.zip(response,favor)
.flatMapLatest { response,favor -> Observable<[PhotosResultCellviewmodel]> in
guard let query = self.passValues.resultQuery else { return .just([]) }
let viewmodels = response.photo.map { photo -> PhotosResultCellviewmodel in
if let saved = favor[query.searchText] { // check had saved favorites photos
return PhotosResultCellviewmodel(photo: photo,wasFavorite: saved.contains(photo))
} else {
return PhotosResultCellviewmodel(photo: photo,wasFavorite: false)
}
}
return Observable.just(viewmodels)
}
.enumerated()
.map { (index,cellviewmodels) in [ResultCellSection(model: "Section:\(index + 1)",items: cellviewmodels)] }
.share()
//.debug("\n\n======= On section reload >>\n\n ")
let saved = tappedShare
.filter { $0.0 == false }
.withLatestFrom(sectionOfCells) { (elements,sections) -> ((Bool,IndexPath),Photo) in
let (_,indexPath) = elements
let photo = sections[indexPath.section].items[indexPath.row].photo
return (elements,photo)
} // 數值正確
.flatMap { [weak self] (elements,photo) -> Observable<((Bool,Photo)> in
let result = self?.saveFavoriteUseCase(of: photo)
.catchError({ error -> Observable<Photo> in
return .error(error)
}) ?? .error(NSError(domain: "Save favorite Failed",code: -991,userInfo: nil))
// Notice: 如果是經由 API呼叫或其他task回傳的 Observable,務必直接將其作為回傳目標,後續再轉型。
// 若此處直接回傳 (elelments,photo) 則會丟失進行中的元素傳遞。
return result.map { photo in (elements,photo) }
}
.debug("======= On saved with photo >>:\n\n")
.map { (elements,photo) in elements.1 }
.share()
let removed = tappedShare
.filter { $0.0 }
.withLatestFrom(sectionOfCells) { (elements,photo)
}
.flatMap { [weak self] (elements,photo) in
self?.useCase.removeFavoriteUseCase?
.rx_remove(favorite: photo)
.catchError({ error -> Observable<()> in
return .error(error)
}) ?? .error(NSError(domain: "Remove favorite Failed",code: -992,userInfo: nil))
}
.debug("======= On favorite removed >> \n\n")
.share()
Observable.of(
saved.map { _ in true },removed.map { _ in true }
)
.merge()
.bind(to: onSavedTriggerReload)
.disposed(by: bag)
return ResultOutput(
saved: saved,sectionOfCells: sectionOfCells,removed: removed
)
}
这是我的测试代码:
// at ResultviewmodelTests.swift
func test_triggerToFetch_remotePhotos() throws {
testScheduler = TestScheduler(initialClock: 0)
// Arrange
let observer = testScheduler.createObserver([ResultCellSection].self)
let unuse_buttonTapped = PublishSubject<(Bool,IndexPath)>()
let trigger = testScheduler.createColdobservable([
.next(100,true),.next(200,.next(300,.next(400,true)
])
.asDriver(onErrorJustReturn: false)
.map { _ in }
let input = ResultInput(
triggerFetch: trigger,photoSelected: unuse_buttonTapped
)
let output = viewmodel.transform(input: input)
output.sectionOfCells
.subscribe(observer)
.disposed(by: bag)
// Actoin
testScheduler.start()
// Assert
let result = observer.events
XCTAssertEqual(result.count,1)
XCTAssertEqual(result.first?.value.element?.first?.items.count,5)
}
我用其他方法试过同样的事情,没关系。
func test_triggerToFetch_remotePhotos_blocking() throws {
// Arrange
let buttonTapped = PublishSubject<(Bool,IndexPath)>()
let triggerReload = PublishSubject<Void>()
let input = ResultInput(
triggerFetch: triggerReload.asDriver(onErrorJustReturn: ()),photoSelected: buttonTapped
)
let output = viewmodel.transform(input: input)
let sectionCells = output.sectionOfCells.subscribeOn(concurrentScheduler)
// Actoin
dispatchQueue.main.asyncAfter(deadline: .Now() + 0.5) {
triggerReload.onNext(())
}
let blocking = try sectionCells.toBlocking().first()
// Assert
XCTAssertEqual(blocking?.count,1)
XCTAssertEqual(blocking?.first?.items.count,5)
/* 連續使用兩個 toBlocking() 會導致test 無法跑完,原因未知。
XCTAssertEqual(try sectionCells.toBlocking().first()?.count,1)
XCTAssertEqual(try sectionCells.toBlocking().first()?.first?.items.count,5)
*/
}
希望有人能帮助我...谢谢!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)