RxSwift:如何在Searchbar中进行单元测试搜索并在tableview中显示结果

时间:2017-06-29 08:51:02

标签: swift unit-testing uisearchbar reactive-cocoa rx-swift

所以我一直在使用Rxswift并且它一直运行良好。我设法让我的所有代码都在测试中,但我正在努力弄清楚如何使用searchbar.rx.bindTo测试搜索。

有很多关于如何使用RxSwift在tableview上搜索和返回结果的教程,但是在这些教程中没有一个教程告诉你如何对它进行单元测试。 https://www.thedroidsonroids.com/blog/ios/rxswift-by-examples-1-the-basics/

以上链接显示了我试图通过搜索栏实现并填充TableView的内容。

我试过用RxBlocking测试它,但我的测试似乎都挂了。 systemUnderTest是viewModel 结果是Observable< [T]>从服务中回来。

let results = systemUnderTest.results.toBlocking()
    let noneObservableList = try! results.single()

    //Then
    XCTAssert(noneObservableList?.count == expectedCount)

它挂起了尝试! results.single()并且从不命中断言。任何人都知道如何测试它。

提前致谢。

这是systemUnderTest:

public class SearchViewModel: SearchViewModelContract {

public var query: Variable<String?> = Variable(String.EmptyString())
public var results: Observable<[ThirdPartySite]>
let minimumCharacterCount = 4
let dueTime = 0.3
let disposeBag = DisposeBag()

public init() {
    results = Observable.just([Object]())
    results = query.asObservable().throttle(dueTime, scheduler: MainScheduler.instance).flatMapLatest{
        queryString  -> Observable<Object> in

        if let queryString = queryString {
            if queryString.characters.count >= self.minimumCharacterCount {
                return self.Something(siteName: queryString)
            }
            return Observable.just(Object(in: Object()))
        }
        return Observable.just(Object(in: Object()))
        }.map { results in
            return results.items
        }.catchErrorJustReturn([Object]()).shareReplay(1)
    }
}

1 个答案:

答案 0 :(得分:1)

我有一些建议:

  • queryresults应该都是let而不是vars。您永远不要重置Observable类型。这是功能性意义的一部分。
  • 您似乎正在使用旧版本的RxSwift;我建议你升级。 -编辑:DOH!当然,这是RxSwift的旧版本,这是一个老问题!
  • 嵌入了副作用(网络调用)的
  • 单元测试代码可能是一个巨大的PITA。将副作用提高到更高的水平,以便在没有副作用的情况下进行单元测试。
  • debounce运算符比throttle更适合数据发射。后者更适合触发器。

关于您如何对搜索进行单元测试的主要问题,我发现RxTest取得了很多成功。这是用于生成searchTerm Observable以及用于证明其有效的测试的代码:

extension ObservableType where Element == String? {

    func searchTerm(minCharacterCount: Int = 4, dueTime: RxTimeInterval = .milliseconds(300), scheduler: SchedulerType = MainScheduler.instance) -> Observable<String> {
        return self
            .compactMap { $0 }
            .filter { minCharacterCount <= $0.count }
            .debounce(dueTime, scheduler: scheduler)
    }
}

class Tests: XCTestCase {

    var scheduler: TestScheduler!
    var result: TestableObserver<String>!
    var disposeBag: DisposeBag!

    override func setUp() {
        super.setUp()
        scheduler = TestScheduler(initialClock: 0, resolution: 0.001)
        result = scheduler.createObserver(String.self)
        disposeBag = DisposeBag()
    }

    func testExample() {
        let input = scheduler.createColdObservable([
            .next(1000, Optional.some("")),
            .next(2000, Optional.some("xyz")),
            .next(3000, Optional.some("wxyz")),
            .next(4000, Optional.some("vwxyz")),
            .next(4300, Optional.some("uvwxyz"))
            ])

        input
            .searchTerm(scheduler: scheduler)
            .subscribe(result)
            .disposed(by: disposeBag)

        scheduler.start()

        XCTAssertEqual(result.events, [.next(3300, "wxyz"), .next(4600, "uvwxyz")])
    }
}

flatMapLatest应该放在副作用代码中,这是您不进行单元测试的内容。