Вопрос 1 .Я согласен, вся логика в вашей loginButton
обработке касаний относится к навигации и хорошо вписывается в область контроллера представления.
Вопрос 2 .Вы обнаруживаете необходимость проверить два различных поведения:
- Обрабатывает ли
LoginViewController
нажатие loginButton
? - Нажимается ли
EnterPhoneNumberViewController
настек навигации?
Аналогично @ Даниэль Т. ответ , я бы порекомендовал отделить код, который обрабатывает нажатие, от кода, которыйтолкает новый контроллер вида .
Вы можете сделать это разными способами, мое любимое - иметь делегата навигации в контроллере вида и проверить, что он вызывается.Наряду с этим вы можете проверить, что тип, соответствующий делегату, выполняет push.
protocol LoginViewControllerNavigationDelegate: class {
func showEnterPhoneNumber()
}
func testLoginTapCallsShowEnterPhoneNumber() {
let navigationDelegateSpy = LoginViewControllerNavigationDelegateSpy()
let viewController = ...
viewController.navigationDelegate = navigationDelegateSpy
viewController.beginAppearanceTransition(true, animated: false) // loads the view
viewController.loginButton.sendActions(for: .touchUpInside)
XCTAssertTrue(navigationDelegateSpy.showEnterPhoneNumberCalled)
}
class LoginViewControllerNavigationDelegateSpy: LoginViewControllerNavigationDelegate {
private(set) var showEnterPhoneNumberCalled = false
func showEnterPhoneNumber() {
showEnterPhoneNumberCalled = true
}
}
В вашем контроллере представления вы бы заменили прямое push EnterPhoneNumberViewController
на
loginButton?.rx.tap
.subscribe(onNext:{ [weak self] in
self?.navigationDelegate?.showEnterPhoneNumber()
})
.disposed(by: disposeBag)
Какой компонент соответствует LoginViewControllerNavigationDelegate
решать только вам.В идеале это был бы компонент, который представлял LoginViewController
в первую очередь.
Ради этого примера давайте предположим, что это выделенный объект, назовем его LoginNavigator
.
func testShowEnterPhoenNumber() {
let navigationController = UINavigationController(rootViewController: UIViewController())
let navigator = LoginNavigator(navigationController)
navigator.showEnterPhoneNumber()
XCTAssertTrue(navigationController.topViewController is EnterPhoneNumberViewController)
}
Этот подход требует немного больше работы, но его преимущество состоит в том, что он не связан.Если вам когда-нибудь понадобится изменить способ представления EnterPhoneNumberViewController
, скажем, от толчка до модального, вы можете сделать это в централизованном и выделенном месте, без необходимости копаться в LoginViewController
.