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

Async network logic testing using Protocol (Test Stub)

Wooseong Kim
December 13, 2017

Async network logic testing using Protocol (Test Stub)

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

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.