Kiểm tra ngày sinh nghe như việc đơn giản nhất trong mọi biểu mẫu: người dùng chọn một ngày, hệ thống lưu lại. Nhưng đây lại là trường sinh ra nhiều lỗi im lặng nhất, vì phần lớn chúng chỉ lộ ra vào một ngày hiếm trong bốn năm hoặc ở một múi giờ khác. Bài này đi qua những trường hợp biên thường gặp và cách xử lý từng trường hợp.
Vì sao ngày 29 tháng 2 hay làm hỏng phép kiểm tra?
Theo lịch Gregorius, một năm là năm nhuận khi chia hết cho 4, nhưng với năm tròn thế kỷ thì phải chia hết cho 400. Nghĩa là năm 1900 không phải năm nhuận, còn năm 2000 thì có. Rất nhiều đoạn kiểm tra chỉ nhớ vế đầu và quên vế sau, nên chúng chấp nhận một ngày 29 tháng 2 không tồn tại và từ chối một ngày có thật.
Hệ quả không dừng ở phép kiểm tra. Nếu bạn tự cộng trừ ngày tháng bằng tay thay vì dùng thư viện ngày tháng của nền tảng, một ngày thừa sẽ làm lệch mọi phép tính phía sau. Một hồ sơ sinh ngày 29 tháng 2 có thể bị tính sai tuổi, sai kỳ hạn, hoặc bị đẩy sang một nhánh xử lý mà không ai lường trước.
Cách kiểm tra đúng là dùng thư viện ngày tháng đã được kiểm chứng thay vì tự viết quy tắc nhuận, và luôn thử mẫu ngày 29 tháng 2 trong bộ kiểm thử tự động. Đây là một trong số ít trường hợp mà một dòng dữ liệu thử nhỏ lại phát hiện được lỗi ở nhiều nơi trong hệ thống.
Tuổi được tính thế nào vào đúng ngày sinh?
Tuổi thường được tính theo số lần sinh nhật đã đi qua. Nếu hôm nay đúng là ngày sinh, người đó thường được coi là đã đủ tuổi mới, tức là tuổi vừa tăng thêm một. Đây là quy ước phổ biến, nhưng nó cũng là chỗ dễ lệch đúng một ngày nếu bạn tính bằng cách lấy hiệu số năm rồi trừ đi khi chưa tới sinh nhật.
Vấn đề chỉ trở nên rõ ràng khi có một ngưỡng đi kèm. Với một ngưỡng tuổi tối thiểu, sai một ngày nghĩa là hoặc bạn cho qua một người chưa đủ tuổi, hoặc bạn chặn một người đã đủ tuổi vào đúng sinh nhật của họ. Cả hai đều là lỗi thật, và cả hai đều chỉ xuất hiện trong đúng một ngày nếu bạn không chủ động đưa mẫu biên vào bài kiểm thử.
Một cách tránh nhầm lẫn là luôn so sánh theo ngày chứ không theo số năm. Hãy tính ngày mà người đó đạt ngưỡng, rồi so ngày đó với hôm nay. Cách này ít phụ thuộc vào quy ước làm tròn hơn, và kết quả dễ giải thích khi có người hỏi vì sao hồ sơ bị chặn.
Múi giờ có làm ngày sinh khác đi không?
Có, theo hai cách. Cách thứ nhất là chuyện thời điểm hiện tại. Máy chủ của bạn có thể đang là ngày hôm nay, trong khi người dùng ở nửa kia địa cầu đã sang ngày mới hoặc vẫn còn ở hôm qua. Nếu tuổi được tính theo ngày của máy chủ, một người vừa đủ tuổi tại nơi họ sống vẫn có thể bị chặn.
Cách thứ hai là chuyện lưu trữ. Ngày sinh là một ngày trên lịch, không phải một thời điểm. Nếu bạn lưu nó như một mốc thời gian kèm giờ và múi giờ, thì việc đổi múi giờ khi hiển thị có thể đẩy nó sang ngày trước đó, và người sinh ngày đầu tháng sẽ thấy ngày sinh của mình lùi lại một hôm.
Cách xử lý gọn nhất là giữ ngày sinh ở dạng ngày thuần, không kèm múi giờ, và chỉ dùng múi giờ ở lớp tính tuổi. Khi cần so với một ngưỡng, hãy ghi rõ đang so theo múi giờ nào.
Các loại lịch khác được xử lý ra sao?
Lịch Gregorius không phải lịch duy nhất đang được dùng. Ethiopia, Nepal và Iran có hệ thống lịch riêng, và cùng một ngày sẽ được viết khác nhau ở mỗi nơi. Nếu biểu mẫu của bạn chỉ có một ô chọn ngày theo một loại lịch, người dùng ở những nước đó sẽ phải tự quy đổi, và sai sót là chuyện bình thường.
Trong thực tế, phần lớn hệ thống lưu ngày theo một chuẩn chung rồi hiển thị theo lựa chọn của người dùng. Cách này chấp nhận được, miễn là bạn hiểu rằng ngày hiển thị và ngày lưu không luôn giống nhau. Điều không nên làm là lấy ngày đã hiển thị rồi đem đi so sánh với dữ liệu lưu, vì hai bên có thể đang nói về hai ngày khác nhau.
Dùng công cụ để thử biểu mẫu ngày sinh
Nếu bạn cần nhiều bản ghi có ngày sinh nằm đúng ở các mốc quanh một ngưỡng tuổi, trình tạo dữ liệu danh tính và kiểm thử trực tuyến của trang này sinh ra cả bộ trong vài lần bấm. Bạn có thể chọn quốc gia để ngày sinh đi kèm đúng định dạng và ngôn ngữ của nơi đó, rồi tạo lại nhiều lần để có những độ tuổi khác nhau.
Toàn bộ dữ liệu này là dữ liệu tổng hợp, chỉ dùng cho kiểm thử phần mềm và trình diễn biểu mẫu, không ứng với người có thật và không dùng để mạo danh ai. Sinh nhật trong bản ghi không thuộc về một người nào, nên cũng đừng dùng nó để kiểm tra những thứ đòi hỏi giấy tờ thật.
Cách dùng hiệu quả nhất là lấy một ngày sinh mẫu, rồi tự dịch nó về đúng ngày biên bạn cần: ngay trước ngưỡng một ngày, đúng ngày ngưỡng, và sau ngưỡng một ngày. Ba mẫu đó bao được phần lớn lỗi tính tuổi. Phần còn lại, tức những mốc phức tạp hơn như ngày 29 tháng 2, được bàn trong bài kiểm thử xác minh độ tuổi.
Phần dành cho nhà phát triển
Hãy lưu ngày sinh như một ngày thuần, không kèm giờ và không kèm múi giờ. Mọi thứ liên quan tới giờ chỉ nên xuất hiện ở lớp tính tuổi, nơi bạn buộc phải trả lời câu hỏi đang tính theo múi giờ nào. Trộn hai loại thông tin này vào một trường là nguồn gốc của phần lớn lỗi lệch ngày.
Vài điểm nên chốt:
- Tính tuổi bằng cách so hai ngày, không bằng cách trừ năm rồi chỉnh tay. Cách so ngày cho kết quả rõ ràng vào đúng ngày sinh.
- Kiểm tra rằng ngày sinh không nằm ở tương lai và không vượt quá một khoảng hợp lý trong quá khứ; cả hai đều là dấu hiệu của dữ liệu sai hoặc bị người dùng nhập nhầm.
- Tách ô nhập ngày sinh khỏi ô nhập ngày bắt đầu sử dụng dịch vụ. Khi cả hai cùng là một trường, mọi phép kiểm tra sau này đều phải đoán ý người nhập.
- Chuẩn bị sẵn mẫu cho ngày 29 tháng 2 của một năm nhuận, cho ngày cuối cùng của tháng, và cho ngày đầu tiên của năm mới, vì đây là ba chỗ hay lệch nhất.
- Nếu hệ thống có hiển thị tuổi, đừng lưu tuổi như một trường cố định. Tuổi thay đổi theo thời gian, còn ngày sinh thì không.
Khi viết dữ liệu thử cho những trường hợp này, hãy dùng dữ liệu tổng hợp và đánh dấu rõ nguồn gốc. Bạn không cần ngày sinh của người thật nào để thử một ranh giới tuổi, và dùng ngày sinh thật chỉ tạo thêm rủi ro về riêng tư mà không giúp bài kiểm thử chắc hơn.
Bước tiếp theo
Hãy viết ba mẫu thử quanh ngưỡng tuổi mà sản phẩm của bạn đang dùng: trước một ngày, đúng ngày, và sau một ngày. Sau đó mở trình tạo dữ liệu danh tính để sinh bản ghi nền, chỉnh ngày sinh về ba mốc đó, và chạy lại bộ kiểm thử để xem hệ thống có xử lý đúng vào đúng những ngày hiếm gặp hay không.