Validate đăng kí user và TDD
swift
51
ios
42
White

VietHQ viết ngày 10/08/2017

Giới thiệu

Việc xác thực quá trình đăng kí mới là công việc mà coder nào cũng phải gặp, thậm chí nó quen thuộc đến mức như cầm đũa hàng ngày vậy. Chúng ta có thể thực hiện việc validate ngay trên viewcontroller, tuy nhiên cách này khó test và sẽ khó quản lý nếu có nhiều điều kiện đầu vào. Cách hay hơn là chúng ta có thể tách ra 1 object validator nhận thông tin đầu vào và trả ra thông báo thành công nếu thông tin nhập vào đúng, trả ra mã lỗi nếu thông tin nhập vào sai.

Mình sẽ làm một ví dụ đơn giản thực hiện việc đăng ký mới user với các điều kiện: xác thực format email, xác thực password lớn hơn 8 ký tự có ít nhất 1 kí tự dạng số và ít nhất 1 ký tự dạng chữ và viết test cho việc validate.

Chuẩn bị toy

Mình tạo một enum Error chứa các case lỗi có thể phát sinh, ở đây để đơn giản chỉ có 2 case. Tiếp theo là một protocol hỗ trợ check thông tin và trả ra mã lỗi, tất cả các object validator sẽ implement protocol này.

enum ONRegisterUserError : Error {
    case invalidEmail
    case invalidPassword
}

protocol ONRegisterUserProtocol {
    var error: ONRegisterUserError { get }
    func isValid() -> Bool
}

Xác thực và test

Mình sẽ bắt đầu với việc xác thực format email, sử dụng protocol ONRegisterUserProtocol như ở trên

class ONEmailValidateItem: ONRegisterUserProtocol {
    var error: ONRegisterUserError = .invalidEmail
    private let email: String

    init(email: String) {
        self.email = email
    }

    func isValid() -> Bool {
        return true
    }
}

Ở đây mình chưa implement hàm isValid (chỉ để 1 giá trị default là true trước), công việc trước nhất là viết unit test.
Mình tạo lớp ONTestEmailValid kế thừa XCTestCase trong thư mục [ProjectName]Tests ([ProjectName] là tên project của bạn).
Chú ý: nhớ thêm dòng @testable import [Projectname]

@testable import ONRegisterUser

class ONTestEmailValid: XCTestCase {
    func testEmailInvalidCharacter() {
        let isValid = ONEmailValidateItem(email: "example@gmail,com").isValid()
        XCTAssertFalse(isValid)
    }

    func testEmailInvalidProvider() {
        let isValid = ONEmailValidateItem(email: "example@.com").isValid()
        XCTAssertFalse(isValid)
    }

    func testEmailInvalidInComplete() {
        let isValid = ONEmailValidateItem(email: "example@").isValid()
        XCTAssertFalse(isValid)
    }

    func testEmailInvalidUserName() {
        let isValid = ONEmailValidateItem(email: "@a.com").isValid()
        XCTAssertFalse(isValid)
    }

    func testEmailValid() {
        let isValid = ONEmailValidateItem(email: "example@a.com").isValid()
        XCTAssertTrue(isValid)
    }
}

Khi build test (command u) thì các test case hầu hết là fail :D

alt text

Bây giờ mới đến bước implement hàm isValid để nó pass tất cả các case mình định nghĩa

func isValid() -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
    let emailTest = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
    return emailTest.evaluate(with: self.email)
}

Để nhanh chóng thì mình sử dụng NSPredicateregEx cho việc filter (regEx thì copy qua google xài luôn thôi :D).
check password làm tương tự như cách triển khai class ONTestEmailValid.

Sau khi implement lại hàm isValid, chúng ta chạy lại test, Done!

alt text

OK, chúng ta đã có 2 class thực thi chức năng validate riêng biệt. Tiếp theo, mình xây dựng đối tượng đảm nhận việc quản lý các validator. Mục đích cho việc tạo lớp này là nhận đầu vào input và đưa ra output chung cho tất cả các validator.

class ONValidateRegisterUser {

    enum ONRegisterResult {
        case success(String)
        case fail(String)
    }

    let result: ONRegisterResult

    init(email: String, password: String) {
        let validator: [ONRegisterUserProtocol] = [ONEmailValidateItem(email: email),
                                                   ONPasswordValidateItem(password: password)]
        let invalids = validator.filter { !$0.isValid() }

        if invalids.count > 0 {
            self.result = .fail("Wrong format")
        } else {
            self.result = .success("Done")
        }
    }
}

Mình tạo enum ONRegisterResult trả về case success khi cả email và pass đều validate thành công, ngược lại ra fail.
Khi đó ở Viewcontroller ta chỉ đơn giản làm như sau

let validator = ONValidateRegisterUser(email: self.userNameTextField.text!, password: self.passwordTextField.text!)

switch validator.result {
case .success(let str):
    SHOW_ALERT(message: str, vc: self)
case .fail(let str):
    SHOW_ALERT(message: str, vc: self)
}

Tổng hợp

Tóm lược bài viết: để thực hiện việc register và TDD ta chú ý 3 việc sau:

  • Tạo các lớp validator check đầu vào như username, password,...
  • Tạo một lớp quản lý các validator, nhận đầu vào là các dữ liệu cần validate và trả ra result.
  • Test trước khi code :D

Source code

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

VietHQ

9 bài viết.
4 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
5 1
Thời gian đầu làm việc với objc mình khá băn khoăn trong việc sử dụng các thuộc tính trong property như strong, weak, copy, assign. Nhân lúc rảnh r...
VietHQ viết gần 3 năm trước
5 1
White
4 0
1. Giới thiệu Từ hồi mới bắt đầu làm IOS, thằng nào cũng hỏi mình có biết sử dụng AFNetworking không? Khổ nỗi lúc đó, mình mới chuyển từ làm game ...
VietHQ viết 9 tháng trước
4 0
White
2 2
1.Tản mạn Cách đơn giản nhất để giảm bớt bug là viết code ít đi. Chân lý đó đã được đưa vào một định luật nổi tiếng, hồi phổ thông ai cũng từng ki...
VietHQ viết 9 tháng trước
2 2
Bài viết liên quan
White
11 4
(Link) (Link) (Link) Ở 2 phần tut trước, mình đã hướng dẫn khá chi tiết cách viết một ứng dụng camera có tích hợp chức năng nhận diện khuôn mặ...
HoangPH viết gần 3 năm trước
11 4
White
0 0
RxSwift: Bài 6: RxCocoa (Part 4) Units 1. Khái niệm chung RxCocoa cung cấp nhiều tính năng mới để làm việc với Cocoa và UIKit 1 cách dễ dàng hơn....
Bùi Khánh Duy viết 18 giờ trước
0 0
White
2 0
Có nhiều cách viết blog công nghệ hơn là làm bánh hay làm tình. Những ngày này Hà Nội mưa liên miên, được cái mát giời, mình lại tức cảnh sinh tìn...
VietHQ viết 7 tháng trước
2 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
9 bài viết.
4 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!