Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Async network logic testing using Protocol (Tes...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Wooseong Kim Wooseong Kim
December 13, 2017

Async network logic testing using Protocol (Test Stub)

presented at Swift Korea meetup (2017/12/13)

Avatar for Wooseong Kim

Wooseong Kim

December 13, 2017
Tweet

More Decks by Wooseong Kim

Other Decks in Programming

Transcript

  1. protocol AuthServiceType { func logIn(id: String, pw: String, ...) }

    // Production class AuthService: AuthServiceType { func logIn(id: String, pw: String, ...) { // Networking logic } }
  2. protocol AuthServiceType { func logIn(id: String, pw: String, ...) }

    // Production class AuthService: AuthServiceType { func logIn(id: String, pw: String, ...) { // Networking logic } } // Test class StubAuthService: AuthServiceType { func logIn(id: String, pw: String, ...) { // Stub logic } }
  3. // Production class LogInViewController: UIViewController { var authService: AuthServiceType! ...

    } let viewController = LogInViewController() viewController.authService = AuthService() // Test let viewController = LogInViewController() viewController.authService = StubAuthService()
  4. // Should store the token after logged in class LogInViewController:

    UIViewController { var authService: AuthServiceType! func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in // Completion logic } } }
  5. protocol AuthServiceType { func logIn(id: String, pw: String, completion: (Response)

    -> Void) } // Production class AuthService: AuthServiceType { func logIn(id: String, pw: String, completion: (Response) -> Void) { // Networking logic } } // Test class StubAuthService: AuthServiceType { func logIn(id: String, pw: String, completion: (Response) -> Void) { // Stub logic } }
  6. // Test class StubAuthService: AuthServiceType { func logIn(id: String, pw:

    String, completion: (Response) -> Void) { let response = Response(token: "token") // Works synchronously completion(response) } }
  7. // Test class StubAuthService: AuthServiceType { func logIn(id: String, pw:

    String, completion: (Response) -> Void) { let response = Response(token: "token") completion(response) } } // Production class LogInViewController: UIViewController { func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in // Passed to here! } } }
  8. func testLogIn() { // given let viewController = LogInViewController() viewController.authService

    = StubAuthService() // when viewController.logInButtonDidTap() }
  9. func testLogIn() { // given let viewController = LogInViewController() viewController.authService

    = StubAuthService() // when viewController.logInButtonDidTap() // then XCTAssertEqual(viewController.token, "token") }
  10. func testLogIn() { // given let viewController = LogInViewController() viewController.authService

    = StubAuthService() // when viewController.logInButtonDidTap() // then XCTAssertEqual(viewController.token, "token") // Failed }
  11. // Production class LogInViewController: UIViewController { var authService: AuthServiceType! var

    token: String func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in self.token = response.token } } }
  12. // Production class LogInViewController: UIViewController { var authService: AuthServiceType! var

    token: String func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in self.token = response.token } } } // Test func testLogIn() { ... XCTAssertEqual(viewController.token, "token") // Succeeded }
  13. class StubAuthService: AuthServiceType { func logIn(id: String, pw: String, completion:

    (Response) -> Void) { let response = Response(token: "token") // Success case completion(response) } }
  14. class StubAuthService: AuthServiceType { func logIn(id: String, pw: String, completion:

    (Response) -> Void) { let response = Response(token: "token") // Success case completion(response) } } func testLogIn_success() { ... XCTAssertEqual(viewController.token, "token") } func testLogIn_wrongPassword() { ...? }
  15. class StubAuthService: AuthServiceType { var stubResponse: Response! func logIn(id: String,

    pw: String, completion: (Response) -> Void) { completion(stubResponse) } }
  16. class StubAuthService: AuthServiceType { var stubResponse: Response! func logIn(id: String,

    pw: String, completion: (Response) -> Void) { completion(stubResponse) } } func testLogIn_success() { let authService = StubAuthService() authService.stubResponse = Response(token: "token") ... viewController.logInButtonDidTap() XCTAssertEqual(viewController.token, "token") }
  17. class StubAuthService: AuthServiceType { var stubResponse: Response! func logIn(id: String,

    pw: String, completion: (Response) -> Void) { completion(stubResponse) } } func testLogIn_success() { ... } func testLogIn_wrongPassword() { let authService = StubAuthService() authService.stubResponse = Response(error: LogInError.wrongPassword) ... viewController.logInButtonDidTap() XCTAssertEqual(viewController.logInError, LogInError.wrongPassword) }
  18. class StubAuthService: AuthServiceType { var stubResponse: Response! func logIn(id: String,

    pw: String, completion: (Response) -> Void) { completion(stubResponse) } } func testLogIn_success() { ... } func testLogIn_wrongPassword() { let authService = StubAuthService() authService.stubResponse = Response(error: LogInError.wrongPassword) ... viewController.logInButtonDidTap() XCTAssertEqual(viewController.logInError, LogInError.wrongPassword) }
  19. enum LogInError { case wrongPassword case idNotExist } class LogInViewController:

    UIViewController { var authService: AuthServiceType! var token: String var logInError: LogInError func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in if response.status == .success { self.token = response.token } else if response.status == .failure { self.logInError = response.error } } } }
  20. enum LogInError { case wrongPassword case idNotExist } class LogInViewController:

    UIViewController { var authService: AuthServiceType! var token: String var logInError: LogInError func logInButtonDidTap() { authService.logIn(id: "id", pw: "pw", completion: { response in if response.status == .success { self.token = response.token } else if response.status == .failure { self.logInError = response.error } } } } func testLogIn_wrongPassword() { ... // Succeeded XCTAssertEqual(viewController.logInError, LogInError.wrongPassword) }
  21. Summary Tests may fail because of network dependency …so let’s

    write test codes with Test Stub May the Test Stub be with you.