Я пытаюсь добавить тесты в существующую кодовую базу.
Приложение использует RxSwift с шаблоном координатора.
AppCoordinator
выглядит как -
import UIKit
import RxSwift
enum AuthenticationState {
case unknown, signedIn, signedOut
}
final class AppCoordinator: BaseCoordinator<Void> {
private let window: UIWindow
init(window: UIWindow) {
self.window = window
}
override func start() -> Observable<Void> {
coordinateToRoot(basedOn: .unknown)
return .never()
}
/// Recursive method that will restart a child coordinator after completion.
/// Based on:
/// https://github.com/uptechteam/Coordinator-MVVM-Rx-Example/issues/3
private func coordinateToRoot(basedOn state: AuthenticationState) {
switch state {
case .unknown:
return showStartScene()
.subscribe(onNext: { [weak self] authState in
self?.window.rootViewController = nil
self?.coordinateToRoot(basedOn: authState)
})
.disposed(by: disposeBag)
case .signedOut:
return showAuthenticationFlow()
.subscribe(onNext: { [weak self] authState in
self?.window.rootViewController = nil
self?.coordinateToRoot(basedOn: authState)
})
.disposed(by: disposeBag)
case .signedIn:
return startHomeFlow()
.subscribe(onNext: { [weak self] authState in
self?.window.rootViewController = nil
self?.coordinateToRoot(basedOn: authState)
})
.disposed(by: disposeBag)
}
}
private func showStartScene() -> Observable<AuthenticationState> {
let coordinator = StartCoordinator(window: window)
return coordinate(to: coordinator).map { _ in return dependencies.authSvc.authState }
}
private func showAuthenticationFlow() -> Observable<AuthenticationState> {
let coordinator = AuthCoordinator(window: window)
return coordinate(to: coordinator).map { _ in return dependencies.authSvc.authState }
}
private func startHomeFlow() -> Observable<AuthenticationState> {
let coordinator = HomeCoordinator(window: window)
return coordinate(to: coordinator).map { _ in return dependencies.authSvc.authState }
}
}
Процесс выглядит следующим образом - start
вызывает метод showStartScene
. Это проверит, существует ли токен и должен ли пользователь видеть экран подключения. Когда все завершено, он генерирует событие, вызывающее вызов coordinateToRoot
, используя самое последнее состояние авторизации, чтобы направить пользователя к правильному Coordinator
Я смог добавить начальный тест, чтобы утверждать, чтоwindow.rootViewController
установлен при запуске, однако я хотел бы заявить о поведении вокруг coordinateToRoot
class AppCoordinatorTests: XCTestCase {
var sut: AppCoordinator!
var window: UIWindow!
var disposeBag: DisposeBag!
override func setUp() {
super.setUp()
window = UIWindow(frame: .zero)
sut = AppCoordinator(window: window)
disposeBag = DisposeBag()
}
override func tearDown() {
super.tearDown()
window = nil
sut = nil
disposeBag = nil
}
func test_on_start_root_view_is_not_nil() {
sut.start()
.subscribe()
.disposed(by: disposeBag)
XCTAssertNotNil(window.rootViewController)
}
}
Каждый координатор генерирует Void
, а затем использует карту в текущей службе аутентификации для вызова рекурсивного метода. и вызвать следующий, действительный координатор.
Я думал, что, возможно, я отправляю событие на текущем координаторе, предварительно установив результат dependencies.authSvc.authState
. Затем я могу утверждать тип UIViewController
, установленный как * 1025. *
например -
XCTAssertTrue((window.rootViewController as Any) is SomeTypeOfViewController)
Я хотел бы знать, что сделало бы этот класс более тестируемым, не делая все просто public
.
Я рассмотрел использование внедрения зависимостей для настройки дочерних координаторов, а затем использование заглушки для имитации событий, я не уверен, что это лучший вариант в контексте чего-то вроде RxSwift