如何在此测试中返回 observable 的下一个值?

Posted

技术标签:

【中文标题】如何在此测试中返回 observable 的下一个值?【英文标题】:How can I return the next value of an observable in this test? 【发布时间】:2019-08-05 14:49:26 【问题描述】:

我正在开发一个基于以下应用的项目:

MVVMC-SplitViewController

我正在尝试围绕BaseCoordinator 类编写单元测试。

我想在类中断言这个方法

private func free<T: CoordinatorType>(coordinator: T) 
    childCoordinators[coordinator.identifier] = nil

实际上确实将协调器从childCoordinators 字典中释放出来。

但我不确定如何做到这一点。我以为我可以简单地创建一个模拟协调器并让start 方法返回一些东西,但我相信我做错了

我的测试

func test_releases_coordinator_from_child_coordinator_dict() 
    class MockCoordinator: BaseCoordinator<Void> 
        override func start() -> Observable<Void> 
            return .empty()
        
    

    let mockCoordinator = MockCoordinator()
    let sut = BaseCoordinator<Void>()

    sut.coordinate(to: mockCoordinator).subscribe().disposed(by: disposeBag)

    XCTAssertEqual(sut.childCoordinators.count, 0)


我的基地协调员

   import RxSwift

    /// Base abstract coordinator generic over the return type of the `start` method.
    class BaseCoordinator<ResultType>: CoordinatorType 

        /// Typealias which allows to access a ResultType of the Coordainator by `CoordinatorName.CoordinationResult`.
        typealias CoordinationResult = ResultType

        /// Utility `DisposeBag` used by the subclasses.
        let disposeBag = DisposeBag()

        /// Unique identifier.
        internal let identifier = UUID()

        /// Dictionary of the child coordinators. Every child coordinator should be added
        /// to that dictionary in order to keep it in memory.
        /// Key is an `identifier` of the child coordinator and value is the coordinator itself.
        /// Value type is `Any` because Swift doesn't allow to store generic types in the array.
        private(set) var childCoordinators = [UUID: Any]()

        /// Stores coordinator to the `childCoordinators` dictionary.
        ///
        /// - Parameter coordinator: Child coordinator to store.
        private func store<T: CoordinatorType>(coordinator: T) 
            childCoordinators[coordinator.identifier] = coordinator
        

        /// Release coordinator from the `childCoordinators` dictionary.
        ///
        /// - Parameter coordinator: Coordinator to release.
        private func free<T: CoordinatorType>(coordinator: T) 
            childCoordinators[coordinator.identifier] = nil
        

        /// 1. Stores coordinator in a dictionary of child coordinators.
        /// 2. Calls method `start()` on that coordinator.
        /// 3. On the `onNext:` of returning observable of method `start()` removes coordinator from the dictionary.
        ///
        /// - Parameter coordinator: Coordinator to start.
        /// - Returns: Result of `start()` method.
        func coordinate<T: CoordinatorType, U>(to coordinator: T) -> Observable<U> where U == T.CoordinationResult 
            store(coordinator: coordinator)
            return coordinator.start()
                .do(onNext:  [weak self] _ in self?.free(coordinator: coordinator) )
        

        /// Starts job of the coordinator.
        ///
        /// - Returns: Result of coordinator job.
        func start() -> Observable<ResultType> 
            fatalError("Start method should be implemented.")
        
    

【问题讨论】:

【参考方案1】:

您不能在MockCoordinator 中使用.empty 作为返回类型。

empty 创建一个 Observable,它不发出任何项目但不会失败地终止。

您应该更新您的模拟,以便在订阅后也发出一个值,例如:

class MockCoordinator: BaseCoordinator<Bool> 
    override func start() -> Observable<Bool> 
        return .of(true)
    

应该调用调用来释放你的协调器。

【讨论】:

以上是关于如何在此测试中返回 observable 的下一个值?的主要内容,如果未能解决你的问题,请参考以下文章

Observable 完成后返回项目列表

从服务返回的 Observable 的单元测试值(使用异步管道)

如何在 Observable.create (RxSwift) 中返回/转发一个 observable

如何从订阅中返回 observable

如何正确返回一个 void Observable?

Angular 8 karma 从服务中测试 Observable 的成功和错误