[TDD] Integrating AuthManager and SessionManager

Muhammad Alfiansyah
2 min readFeb 6, 2025

Since we are following a dependency injection pattern, both AuthManager and SessionManager will depend on a storage solution for user data persistence (e.g., SessionStorage).

Refactored AuthManager

protocol AuthServiceProtocol {
func signIn(completion: @escaping (User?) -> Void)
func signOut()
}

class AuthManager {
private let authService: AuthServiceProtocol
private let sessionManager: SessionManager

init(
authService: AuthServiceProtocol,
sessionManager: SessionManager
) {
self.authService = authService
self.sessionManager = sessionManager
}

func signIn(callback: @escaping (User?) -> Void) {
authService.signIn { [weak self] user in
if let user = user {
self?.sessionManager.saveUser(user)
}
callback(user)
}
}

func signOut() {
authService.signOut()
}
}

Now that AuthManager and SessionManager are integrated, you can write tests for this flow to make sure sign-in and sign-out behavior works as expected.

class AuthManagerTests: XCTestCase {
var authManager: AuthManager!
var mockAuthService: MockAuthService!
var mockStorage: MockStorage!

override func setUp() {
super.setUp()
mockStorage = MockStorage()
let sessionManager = SessionManager(storage: mockStorage)
mockAuthService = MockAuthService()
authManager = AuthManager(
authService: mockAuthService,
sessionManager: sessionManager)
}

func testSignInSuccess() {
mockAuthService.user = User(id: 123, name: "John Doe", email: "john@example.com")
let expectation = self.expectation(description: "Sign in should succeed")

authManager.signIn { user in
XCTAssertNotNil(user, "User should be not nil")
XCTAssertNotNil(self.mockStorage.storageUser, "User should be saved to session")
expectation.fulfill()
}

wait(for: [expectation], timeout: 1.0)
}

func testSignInFailure() {
mockAuthService.user = nil
let expectation = self.expectation(description: "Sign in should fail")

authManager.signIn { user in
XCTAssertNil(user, "Expected sign-in to be fail")
expectation.fulfill()
}

wait(for: [expectation], timeout: 1.0)
}

func testSignOut() {
authManager.signOut()
XCTAssert(true, "Sign-out function executed succesfully")
}
}
  • AuthManager handles authentication logic and relies on SessionManager to persist the user session.
  • SessionManager abstracts the session persistence mechanism, allowing you to easily swap storage (e.g., UserDefaults, Keychain) later.
  • Unit tests ensure correctness by mocking both authentication and session storage behavior, so no real API calls or storage operations are made during tests.

--

--

No responses yet