RxTest,为什么结果不在期望计数中

问题描述

我有一个演示项目来获取远程照片数据,当用户点击收藏夹按钮时,它会在本地数据库中记录照片。

抱歉我的英语不好...

问题: 当我尝试使用 RxTest 期待 ResultviewmodelsectionOfCells 结果有时会是 1 或 2 或 3。像图像:

enter image description here

enter image description here

为什么结果计数不是 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 (将#修改为@)