在ViewController中可以观察到单元测试RxSwift

Sha*_*ave 5 unit-testing ios swift rx-swift

我对RxSwift很陌生。我有一个具有预输入/自动完成功能的视图控制器(即,UITextField中的用户类型,并且只要他们输入至少2个字符,就会发出网络请求以搜索匹配建议)。控制器viewDidLoad调用以下方法来设置Observable:

class TypeaheadResultsViewController: UIViewController {

var searchTextFieldObservable: Observable<String>!
@IBOutlet weak var searchTextField: UITextField!
private let disposeBag = DisposeBag()
var results: [TypeaheadResult]?

override func viewDidLoad() {
    super.viewDidLoad()
    //... unrelated setup stuff ...
    setupSearchTextObserver()
}

func setupSearchTextObserver() {
            searchTextFieldObservable =
                self.searchTextField
                    .rx
                    .text
                    .throttle(0.5, scheduler: MainScheduler.instance)
                    .map { $0 ?? "" }

            searchTextFieldObservable
                .filter { $0.count >= 2 }
                .flatMapLatest { searchTerm in self.search(for: searchTerm) }
                .subscribe(
                    onNext: { [weak self] searchResults in
                        self?.resetResults(results: searchResults)
                    },
                    onError: { [weak self] error in
                        print(error)
                        self?.activityIndicator.stopAnimating()
                    }
                )
                .disposed(by: disposeBag)

            // This is the part I want to test:        
            searchTextFieldObservable
                .filter { $0.count < 2 }
                .subscribe(
                    onNext: { [weak self] _ in
                        self?.results = nil
                    }
                )
                .disposed(by: disposeBag)
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常,但是我正在努力找出如何对的行为进行单元测试searchTextFieldObservable。为简单起见,我只想通过单元测试来验证将results设置为nilwhen searchTextField更改事件后少于2个字符的时间。
我尝试了几种不同的方法。我的测试目前看起来像这样:

    class TypeaheadResultsViewControllerTests: XCTestCase {
        var ctrl: TypeaheadResultsViewController!

        override func setUp() {
            super.setUp()
            let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
            ctrl = storyboard.instantiateViewController(withIdentifier: "TypeaheadResultsViewController") as! TypeaheadResultsViewController
        }

        override func tearDown() {
            ctrl = nil
            super.tearDown()
        }

        /// Verify that the searchTextObserver sets the results array
        /// to nil when there are less than two characters in the searchTextView
        func testManualChange() {
          // Given: The view is loaded (this triggers viewDidLoad)
          XCTAssertNotNil(ctrl.view)
          XCTAssertNotNil(ctrl.searchTextField)
          XCTAssertNotNil(ctrl.searchTextFieldObservable)

          // And: results is not empty
          ctrl.results = [ TypeaheadResult(value: "Something") ]

          let tfObservable = ctrl.searchTextField.rx.text.subscribeOn(MainScheduler.instance)
          //ctrl.searchTextField.rx.text.onNext("e")
          ctrl.searchTextField.insertText("e")
          //ctrl.searchTextField.text = "e"
          do {
              guard let result =
                try tfObservable.toBlocking(timeout: 5.0).first() else { 
return }
            XCTAssertEqual(result, "e")  // passes
            XCTAssertNil(ctrl.results)  // fails
        } catch {
            print(error)
        }
    }
Run Code Online (Sandbox Code Playgroud)

基本上,我想知道如何手动/以编程方式在searchTextFieldObservable(或最好在searchTextField)上触发事件,以触​​发第二个订阅中标记为“这是我要测试的部分:”的代码。

kiw*_*sip 0

问题是self.ctrl.searchTextField.rx.text.onNext("e")不会触发searchTextFieldObservable onNext订阅。

如果像这样直接设置文本值,也不会触发订阅self.ctrl.searchTextField.text = "e"

如果您像这样设置 textField 值,订阅将触发(并且您的测试应该成功)self.ctrl.searchTextField.insertText("e")

我认为这样做的原因是UITextField.rx.text观察来自 的方法UIKeyInput