From 38a9098a55c27770702fe2a6847aff934eaa9781 Mon Sep 17 00:00:00 2001 From: DeluxeAlonso Date: Sun, 9 Jul 2023 00:07:41 -0500 Subject: [PATCH 1/3] Implements MockSignInViewModelProtocol --- UpcomingMovies.xcodeproj/project.pbxproj | 4 ++ .../SignInViewControllerTests.swift | 66 +++++++++++++++++++ .../Account/AuthenticationMockFactory.swift | 19 ++++++ 3 files changed, 89 insertions(+) create mode 100644 UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift diff --git a/UpcomingMovies.xcodeproj/project.pbxproj b/UpcomingMovies.xcodeproj/project.pbxproj index cb75e5faf..e9e17ce5e 100644 --- a/UpcomingMovies.xcodeproj/project.pbxproj +++ b/UpcomingMovies.xcodeproj/project.pbxproj @@ -311,6 +311,7 @@ E2A024AA256F6B7600D2018C /* SmallWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A024A9256F6B7600D2018C /* SmallWidgetView.swift */; }; E2A076612A29B02F0089062F /* MockNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A076602A29B02F0089062F /* MockNavigationController.swift */; }; E2A104B029EFA1B400DA0809 /* MovieDetailPosterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A104AF29EFA1B400DA0809 /* MovieDetailPosterViewController.swift */; }; + E2A322F62A5A722C00AC0C2A /* SignInViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A322F52A5A722C00AC0C2A /* SignInViewControllerTests.swift */; }; E2A4D9362511B05500571893 /* AuthenticationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A4D9352511B05500571893 /* AuthenticationAssembly.swift */; }; E2A4D9382511B06000571893 /* ProfileAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A4D9372511B06000571893 /* ProfileAssembly.swift */; }; E2A4D93A2511B0E200571893 /* CustomListsAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A4D9392511B0E200571893 /* CustomListsAssembly.swift */; }; @@ -812,6 +813,7 @@ E2A024A9256F6B7600D2018C /* SmallWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallWidgetView.swift; sourceTree = ""; }; E2A076602A29B02F0089062F /* MockNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNavigationController.swift; sourceTree = ""; }; E2A104AF29EFA1B400DA0809 /* MovieDetailPosterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieDetailPosterViewController.swift; sourceTree = ""; }; + E2A322F52A5A722C00AC0C2A /* SignInViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewControllerTests.swift; sourceTree = ""; }; E2A4D9352511B05500571893 /* AuthenticationAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationAssembly.swift; sourceTree = ""; }; E2A4D9372511B06000571893 /* ProfileAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileAssembly.swift; sourceTree = ""; }; E2A4D9392511B0E200571893 /* CustomListsAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListsAssembly.swift; sourceTree = ""; }; @@ -2291,6 +2293,7 @@ E26578B52A40F26B00D8A071 /* SignInCoordinatorTests.swift */, E2FE17FF2A52A1380033D6A2 /* SignInViewModelTests.swift */, E2BE5AA02A57EB350088B1CD /* SignInInteractorTests.swift */, + E2A322F52A5A722C00AC0C2A /* SignInViewControllerTests.swift */, ); path = Authentication; sourceTree = ""; @@ -3228,6 +3231,7 @@ E2B8C49B28B738E2006A8ECC /* FavoritesSavedMoviesInteractorTests.swift in Sources */, E2A958CC2A3677B70004FC5C /* AccountInteractorTests.swift in Sources */, E2A958D52A367C970004FC5C /* MovieDetailOptionTests.swift in Sources */, + E2A322F62A5A722C00AC0C2A /* SignInViewControllerTests.swift in Sources */, E25DAC8F2A28676D00806501 /* MovieDetailCoordinatorTests.swift in Sources */, E2ACC8B42A3E4AED007FDFC9 /* AuthPermissionViewControllerTests.swift in Sources */, E2A958C82A363FFE0004FC5C /* MovieReviewDetailCoordinatorTests.swift in Sources */, diff --git a/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift new file mode 100644 index 000000000..17f6f6e5b --- /dev/null +++ b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift @@ -0,0 +1,66 @@ +// +// SignInViewControllerTests.swift +// UpcomingMoviesTests +// +// Created by Alonso on 8/07/23. +// Copyright © 2023 Alonso. All rights reserved. +// + +import XCTest +@testable import UpcomingMovies + +final class SignInViewControllerTests: XCTestCase { + + private var viewModel: MockAuthPermissionViewModel! + private var coordinator: MockAuthPermissionCoordinator! + private var delegate: MockAuthPermissionViewControllerDelegate! + + override func setUpWithError() throws { + try super.setUpWithError() + viewModel = MockAuthPermissionViewModel() + coordinator = MockAuthPermissionCoordinator() + delegate = MockAuthPermissionViewControllerDelegate() + } + + override func tearDownWithError() throws { + viewModel = nil + coordinator = nil + delegate = nil + try super.tearDownWithError() + } + + func testCloseBarButtonAction() { + // Arrange + let viewController = createSUT() + _ = viewController.view + coordinator.dismissResult = () + // Act + viewController.perform(Selector("closeBarButtonAction"), with: nil) + // Assert + XCTAssertEqual(coordinator.dismissCallCount, 1) + XCTAssertEqual(delegate.didReceiveAuthorizationCallCount, 1) + } + + func testPresentationControllerDidDismiss() { + // Arrange + let viewController = createSUT() + _ = viewController.view + coordinator.dismissResult = () + // Act + viewController.presentationControllerDidDismiss(UIPresentationController(presentedViewController: UIViewController(), + presenting: nil)) + // Assert + XCTAssertEqual(coordinator.didDismissCallCount, 1) + XCTAssertEqual(delegate.didReceiveAuthorizationCallCount, 1) + } + + private func createSUT() -> SignInViewController { + let viewController = SignInViewController.instantiate() + viewController.viewModel = viewModel + viewController.coordinator = coordinator + viewController.delegate = delegate + + return viewController + } + +} diff --git a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift index 902a020b8..e8b3fc9f1 100644 --- a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift +++ b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift @@ -86,3 +86,22 @@ final class MockSignInInteractor: SignInInteractorProtocol { } } + +final class MockSignInViewModelProtocol: SignInViewModelProtocol { + + var startLoading: AnyBehaviorBindable = BehaviorBindable(false).eraseToAnyBindable() + var showAuthPermission: AnyPublishBindable = PublishBindable().eraseToAnyBindable() + var didUpdateAuthenticationState = BehaviorBindable(nil).eraseToAnyBindable() + var didReceiveError: AnyPublishBindable = PublishBindable().eraseToAnyBindable() + + private(set) var startAuthorizationProcessCallCount = 0 + func startAuthorizationProcess() { + startAuthorizationProcessCallCount += 1 + } + + private(set) var signInUserCallCount = 0 + func signInUser() { + signInUserCallCount += 1 + } + +} From 1a278181f2c5074f816e26309745da207466f755 Mon Sep 17 00:00:00 2001 From: DeluxeAlonso Date: Sun, 9 Jul 2023 00:10:11 -0500 Subject: [PATCH 2/3] Implements MockSignInCoordinator --- .../SignInViewControllerTests.swift | 8 ++++---- .../Mocks/Account/AuthenticationMockFactory.swift | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift index 17f6f6e5b..1d42f4b88 100644 --- a/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift +++ b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift @@ -11,14 +11,14 @@ import XCTest final class SignInViewControllerTests: XCTestCase { - private var viewModel: MockAuthPermissionViewModel! - private var coordinator: MockAuthPermissionCoordinator! + private var viewModel: MockSignInViewModel! + private var coordinator: MockSignInCoordinator! private var delegate: MockAuthPermissionViewControllerDelegate! override func setUpWithError() throws { try super.setUpWithError() - viewModel = MockAuthPermissionViewModel() - coordinator = MockAuthPermissionCoordinator() + viewModel = MockSignInViewModel() + coordinator = MockSignInCoordinator() delegate = MockAuthPermissionViewControllerDelegate() } diff --git a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift index e8b3fc9f1..25413dd02 100644 --- a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift +++ b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift @@ -87,7 +87,7 @@ final class MockSignInInteractor: SignInInteractorProtocol { } -final class MockSignInViewModelProtocol: SignInViewModelProtocol { +final class MockSignInViewModel: SignInViewModelProtocol { var startLoading: AnyBehaviorBindable = BehaviorBindable(false).eraseToAnyBindable() var showAuthPermission: AnyPublishBindable = PublishBindable().eraseToAnyBindable() @@ -105,3 +105,16 @@ final class MockSignInViewModelProtocol: SignInViewModelProtocol { } } + +final class MockSignInCoordinator: SignInCoordinatorProtocol { + + private(set) var showAuthPermissionCallCount = 0 + func showAuthPermission(for authPermissionURL: URL, and authPermissionDelegate: AuthPermissionViewControllerDelegate) { + showAuthPermissionCallCount += 1 + } + +} + +final class MockSignInViewControllerDelegate: SignInViewControllerDelegate { + +} From e54f7f79554655fe33996b5fb40615de758ffc3b Mon Sep 17 00:00:00 2001 From: DeluxeAlonso Date: Sun, 9 Jul 2023 00:55:29 -0500 Subject: [PATCH 3/3] Adds unit tests for sign in view controller --- .../SignInViewControllerTests.swift | 51 ++++++++++++++----- .../Account/AuthenticationMockFactory.swift | 4 -- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift index 1d42f4b88..abae904d2 100644 --- a/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift +++ b/UpcomingMoviesTests/Account/Authentication/SignInViewControllerTests.swift @@ -13,13 +13,13 @@ final class SignInViewControllerTests: XCTestCase { private var viewModel: MockSignInViewModel! private var coordinator: MockSignInCoordinator! - private var delegate: MockAuthPermissionViewControllerDelegate! + private var delegate: MockSignInViewControllerDelegate! override func setUpWithError() throws { try super.setUpWithError() viewModel = MockSignInViewModel() coordinator = MockSignInCoordinator() - delegate = MockAuthPermissionViewControllerDelegate() + delegate = MockSignInViewControllerDelegate() } override func tearDownWithError() throws { @@ -33,25 +33,52 @@ final class SignInViewControllerTests: XCTestCase { // Arrange let viewController = createSUT() _ = viewController.view - coordinator.dismissResult = () // Act - viewController.perform(Selector("closeBarButtonAction"), with: nil) + viewController.loginButtonAction(()) // Assert - XCTAssertEqual(coordinator.dismissCallCount, 1) - XCTAssertEqual(delegate.didReceiveAuthorizationCallCount, 1) + XCTAssertEqual(viewModel.startAuthorizationProcessCallCount, 1) } - func testPresentationControllerDidDismiss() { + func testDidUpdateAuthenticationState() { // Arrange let viewController = createSUT() _ = viewController.view - coordinator.dismissResult = () // Act - viewController.presentationControllerDidDismiss(UIPresentationController(presentedViewController: UIViewController(), - presenting: nil)) + viewModel.didUpdateAuthenticationState.value = .currentlySignedIn // Assert - XCTAssertEqual(coordinator.didDismissCallCount, 1) - XCTAssertEqual(delegate.didReceiveAuthorizationCallCount, 1) + _ = XCTWaiter.wait(for: [XCTestExpectation(description: "")], timeout: 0.1) + XCTAssertEqual(delegate.didUpdateAuthenticationStateCallCount, 2) + } + + func testShowAuthPermission() { + // Arrange + let viewController = createSUT() + _ = viewController.view + // Act + viewModel.showAuthPermission.send(URL(string: "www.google.com")!) + // Assert + _ = XCTWaiter.wait(for: [XCTestExpectation(description: "")], timeout: 0.1) + XCTAssertEqual(coordinator.showAuthPermissionCallCount, 1) + } + + func testDidReceiveAuthorizationTrue() { + // Arrange + let viewController = createSUT() + _ = viewController.view + // Act + viewController.authPermissionViewController(AuthPermissionViewController(), didReceiveAuthorization: true) + // Assert + XCTAssertEqual(viewModel.signInUserCallCount, 1) + } + + func testDidReceiveAuthorizationFalse() { + // Arrange + let viewController = createSUT() + _ = viewController.view + // Act + viewController.authPermissionViewController(AuthPermissionViewController(), didReceiveAuthorization: false) + // Assert + XCTAssertEqual(viewModel.signInUserCallCount, 0) } private func createSUT() -> SignInViewController { diff --git a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift index 25413dd02..0b3d5951f 100644 --- a/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift +++ b/UpcomingMoviesTests/Helpers/Mocks/Account/AuthenticationMockFactory.swift @@ -114,7 +114,3 @@ final class MockSignInCoordinator: SignInCoordinatorProtocol { } } - -final class MockSignInViewControllerDelegate: SignInViewControllerDelegate { - -}