如何使用RxSwift模拟tableView行选择

时间:2019-03-19 09:20:48

标签: ios swift uitableview xctest rx-swift

我有一个UITableViewController设置,如下所示。

视图控制器

class FeedViewController: BaseTableViewController, ViewModelAttaching {

    var viewModel: Attachable<FeedViewModel>!
    var bindings: FeedViewModel.Bindings {
        let viewWillAppear = rx.sentMessage(#selector(UIViewController.viewWillAppear(_:)))
            .mapToVoid()
            .asDriverOnErrorJustComplete()

        let refresh = tableView.refreshControl!.rx
            .controlEvent(.valueChanged)
            .asDriver()

        return FeedViewModel.Bindings(
            fetchTrigger: Driver.merge(viewWillAppear, refresh),
            selection: tableView.rx.itemSelected.asDriver()
        )
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func bind(viewModel: FeedViewModel) -> FeedViewModel {
        viewModel.posts
            .drive(tableView.rx.items(cellIdentifier: FeedTableViewCell.reuseID, cellType: FeedTableViewCell.self)) { _, viewModel, cell in
                cell.bind(to: viewModel)
            }
            .disposed(by: disposeBag)

        viewModel.fetching
            .drive(tableView.refreshControl!.rx.isRefreshing)
            .disposed(by: disposeBag)

        viewModel.errors
            .delay(0.1)
            .map { $0.localizedDescription }
            .drive(errorAlert)
            .disposed(by: disposeBag)

        return viewModel
    }
}

查看模型

class FeedViewModel: ViewModelType {

    let fetching: Driver<Bool>
    let posts: Driver<[FeedDetailViewModel]>
    let selectedPost: Driver<Post>
    let errors: Driver<Error>

    required init(dependency: Dependency, bindings: Bindings) {

        let activityIndicator = ActivityIndicator()
        let errorTracker = ErrorTracker()

        posts = bindings.fetchTrigger
            .flatMapLatest {
                return dependency.feedService.getFeed()
                    .trackActivity(activityIndicator)
                    .trackError(errorTracker)
                    .asDriverOnErrorJustComplete()
                    .map { $0.map(FeedDetailViewModel.init) }
        }

        fetching = activityIndicator.asDriver()
        errors = errorTracker.asDriver()
        selectedPost = bindings.selection
            .withLatestFrom(self.posts) { (indexPath, posts: [FeedDetailViewModel]) -> Post in
                return posts[indexPath.row].post
        }
    }

    typealias Dependency = HasFeedService

    struct Bindings {
        let fetchTrigger: Driver<Void>
        let selection: Driver<IndexPath>
    }
}

我具有绑定,可以检测到何时选择了行,该绑定触发了其他地方的方法,并提供了一个视图控制器。

我试图断言,当选择一行时,会显示一个视图,但是我无法成功模拟正在选择的行。

我尝试的测试类似

   func test_ViewController_PresentsDetailView_On_Selection() {

        let indexPath = IndexPath(row: 0, section: 0)
        sut.start().subscribe().disposed(by: rx_disposeBag)
        let viewControllers = sut.navigationController.viewControllers

        let vc = viewControllers.first as! FeedViewController
        vc.tableView(tableView, didSelectRowAt: indexPath)

        XCTAssertNotNil(sut.navigationController.presentedViewController)
    }

但这会失败,除了

  

无法识别的选择器已发送到实例

如何模拟在单元测试中选择的行?

1 个答案:

答案 0 :(得分:2)

简短的答案是你不知道。单元测试不是UIView对象和UI对象操作的地方。您想要为这种测试添加UI测试目标。