Ios RxSwift,使用RxBlock的测试不会结束
我尝试测试一个非常简单的视图模型:Ios RxSwift,使用RxBlock的测试不会结束,ios,swift,rx-swift,rx-blocking,Ios,Swift,Rx Swift,Rx Blocking,我尝试测试一个非常简单的视图模型: struct SearchViewModelImpl: SearchViewModel { let query = PublishSubject<String>() let results: Observable<BookResult<[Book]>> init(searchService: SearchService) { results = query .
struct SearchViewModelImpl: SearchViewModel {
let query = PublishSubject<String>()
let results: Observable<BookResult<[Book]>>
init(searchService: SearchService) {
results = query
.distinctUntilChanged()
.throttle(0.5, scheduler: MainScheduler.instance)
.filter({ !$0.isEmpty })
.flatMapLatest({ searchService.search(query: $0) })
}
}
我试图测试从服务接收到的错误,因此我通过以下方式将其加倍:
class SearchServiceStub: SearchService {
let erroring: Bool
init(erroring: Bool) {
self.erroring = erroring
}
func search(query: String) -> Observable<BookResult<[Book]>> {
if erroring {
return .just(BookResult.error(SearchError.downloadError, cached: nil))
} else {
return books.map(BookResult.success) // Returns dummy books
}
}
}
func test_when_searchBooksErrored_then_nextEventWithError() {
let sut = SearchViewModelImpl(searchService: SearchServiceStub(erroring: true))
let observer = scheduler.createObserver(BookResult<[Book]>.self)
scheduler
.createHotObservable([
Recorded.next(200, ("Rx")),
Recorded.next(800, ("RxSwift"))
])
.bind(to: sut.query)
.disposed(by: disposeBag)
sut.results
.subscribe(observer)
.disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(observer.events.count, 2)
}
我正在测试一个错误如下的查询:
class SearchServiceStub: SearchService {
let erroring: Bool
init(erroring: Bool) {
self.erroring = erroring
}
func search(query: String) -> Observable<BookResult<[Book]>> {
if erroring {
return .just(BookResult.error(SearchError.downloadError, cached: nil))
} else {
return books.map(BookResult.success) // Returns dummy books
}
}
}
func test_when_searchBooksErrored_then_nextEventWithError() {
let sut = SearchViewModelImpl(searchService: SearchServiceStub(erroring: true))
let observer = scheduler.createObserver(BookResult<[Book]>.self)
scheduler
.createHotObservable([
Recorded.next(200, ("Rx")),
Recorded.next(800, ("RxSwift"))
])
.bind(to: sut.query)
.disposed(by: disposeBag)
sut.results
.subscribe(observer)
.disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(observer.events.count, 2)
}
首先,我只是断言事件的计数是否正确,但我只收到一个而不是两个。我认为这是一个异步问题,所以我将测试改为使用RxBlock:
func test_when_searchBooksErrored_then_nextEventWithError() {
let sut = SearchViewModelImpl(searchService: SearchServiceStub(erroring: true))
let observer = scheduler.createObserver(BookResult<[Book]>.self)
scheduler
.createHotObservable([
Recorded.next(200, ("Rx")),
Recorded.next(800, ("RxSwift"))
])
.bind(to: sut.query)
.disposed(by: disposeBag)
sut.results.debug()
.subscribe(observer)
.disposed(by: disposeBag)
let events = try! sut.results.take(2).toBlocking().toArray()
scheduler.start()
XCTAssertEqual(events.count, 2)
}
但这永远不会结束
我不知道我的存根是否有问题,或者viewmodel是否有问题,但生产应用程序工作正常,在查询启动时发出事件
RxTest和RXBLOCK的文档非常简短,有一个字符串或整数的经典示例,但与这种流无关。。。这非常令人沮丧。您使用MainScheduler.instance scheduler限制查询。试着移除它,看看会发生什么。这可能就是为什么你只能得到一个。在测试时,您需要将测试调度程序注入该节流阀 有几种不同的方法可以将正确的调度程序引入到您的模型中。根据您当前的代码,依赖项注入可以正常工作
struct SearchViewModelImpl: SearchViewModel {
let query = PublishSubject<String>()
let results: Observable<BookResult<[Book]>>
init(searchService: SearchService, scheduler: SchedulerType = MainScheduler.instance) {
results = query
.distinctUntilChanged()
.throttle(0.5, scheduler: scheduler)
.filter({ !$0.isEmpty })
.flatMapLatest({ searchService.search(query: $0) })
}
}
此外,您可以将结果事件绑定到可测试的观察者,而不是使用toBocking
虽然ToBlock在某些情况下很有用,但当您将事件绑定到testableObserver时,您会获得更多信息。您可以使用MainScheduler.instance scheduler限制查询。试着移除它,看看会发生什么。这可能就是为什么你只能得到一个。在测试时,您需要将测试调度程序注入该节流阀 有几种不同的方法可以将正确的调度程序引入到您的模型中。根据您当前的代码,依赖项注入可以正常工作
struct SearchViewModelImpl: SearchViewModel {
let query = PublishSubject<String>()
let results: Observable<BookResult<[Book]>>
init(searchService: SearchService, scheduler: SchedulerType = MainScheduler.instance) {
results = query
.distinctUntilChanged()
.throttle(0.5, scheduler: scheduler)
.filter({ !$0.isEmpty })
.flatMapLatest({ searchService.search(query: $0) })
}
}
此外,您可以将结果事件绑定到可测试的观察者,而不是使用toBocking
虽然ToBlock在某些情况下很有用,但是当您将事件绑定到testableObserver时,您会获得更多信息。您可以使用MainScheduler.instance scheduler限制查询。试着移除它,看看会发生什么。这可能就是为什么你只能得到一个。在测试时,您需要将测试调度程序注入该节流阀。此外,您可以将结果绑定到观察者,然后检查这些事件,而无需执行let events=try!苏特。结果。采取2。托布洛克。今天你他妈的是对的,@JustinM!现在的问题是如何注入测试调度程序:\n请将此注释转换为答案,我将接受它:但是,除此之外,这只适用于第一种类型的测试,不适用于RxBlock。请给我几分钟时间,我将编写一个工作示例,并将其张贴在您使用MainScheduler.instance scheduler限制查询的文章中。试着移除它,看看会发生什么。这可能就是为什么你只能得到一个。在测试时,您需要将测试调度程序注入该节流阀。此外,您可以将结果绑定到观察者,然后检查这些事件,而无需执行let events=try!苏特。结果。采取2。托布洛克。今天你他妈的是对的,@JustinM!现在的问题是如何注入测试调度程序:\n请将此注释转换为答案,我将接受它:但是,除此之外,这只适用于第一种类型的测试,不适用于RxBlock。请给我几分钟时间,我将编写一个工作示例并发布它