Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Test Data Management

Software Testing Fundamentals Bài 25/60

Mở đầu — vì sao bài này quan trọng

Có một câu tôi hay nói với các bạn tester mới vào nghề: "Test data tốt thì test pass đúng và bắt được bug. Test data tệ thì test pass giả (fake pass) hoặc fail giả (fake fail)." Nghe qua thì đơn giản, nhưng đây chính là ranh giới phân biệt một tester nghiệp dư và một tester chuyên nghiệp.

Bạn thử tưởng tượng: bạn thiết kế 30 test case cực kỳ chỉn chu theo đúng kỹ thuật, viết bug report chuẩn từng dòng, nhưng khi chạy thì tài khoản bạn dùng đã hết hạn, số dư ví bằng 0, hoặc sản phẩm bạn cần test đã bị xóa khỏi database từ hôm qua. Kết quả? Bạn ngồi chờ, ngồi hỏi dev, ngồi tạo lại dữ liệu bằng tay — mất nửa buổi cho một thứ lẽ ra chỉ tốn 5 phút. Tệ hơn, có những bug bạn không bao giờ tìm ra được, đơn giản vì dữ liệu bạn dùng quá "sạch", quá lý tưởng, không bao giờ có tên khách hàng dài 200 ký tự, không bao giờ có địa chỉ chứa dấu tiếng Việt lạ, không bao giờ có đơn hàng với số tiền âm.

Test Data Management (quản lý dữ liệu kiểm thử — thường viết tắt là TDM) là cả một kỷ luật riêng trong QA. Nó trả lời các câu hỏi: dữ liệu để test lấy từ đâu, tạo bằng cách nào, lưu ở đâu, làm mới ra sao, và làm sao để dữ liệu nhạy cảm của khách hàng thật không bị lộ khi đội test dùng nó. Trong bài này, chúng ta sẽ đi sâu vào đúng phần đó — không lan sang cách thiết kế test case (Bài 24) hay cách quản lý môi trường test (Bài 26), mà tập trung vào chính bản thân dữ liệu.

Khái niệm cốt lõi

Test data là gì và vì sao nó khó

Test data đơn giản là mọi dữ liệu đầu vào mà bạn cần để một test case chạy được: tài khoản đăng nhập, sản phẩm trong giỏ hàng, mã giảm giá, hồ sơ khách hàng, file upload, số dư ví... Nghe thì đơn giản, nhưng nó khó vì ba lý do.

Thứ nhất, dữ liệu có trạng thái (state). Một tài khoản có thể đang ở trạng thái "chưa xác thực email", "đã khóa", "đã mua gói premium". Cùng một test case sẽ cho kết quả khác nhau tùy trạng thái này. Thứ hai, dữ liệu có quan hệ (relationships). Một đơn hàng phải gắn với một khách hàng, khách hàng phải có địa chỉ, địa chỉ phải thuộc một tỉnh/thành có thật. Bạn không thể tạo dữ liệu rời rạc. Thứ ba, dữ liệu bị hao mòn (data decay). Test data hôm nay dùng được, ngày mai đồng nghiệp khác chạy test thanh toán đã tiêu hết số dư, hoặc quy trình reset môi trường đã xóa sạch.

Bốn loại test data bạn phải phân biệt

Static data (dữ liệu tĩnh / fixture). Đây là dữ liệu cố định, chuẩn bị sẵn, dùng đi dùng lại và ít khi thay đổi. Ví dụ: danh sách 63 tỉnh/thành Việt Nam, bảng mã ngân hàng, danh mục sản phẩm mẫu. Ưu điểm là ổn định, dễ kiểm soát, test lặp lại cho kết quả nhất quán. Fixture thường được lưu dưới dạng file JSON, CSV, hoặc script SQL seed. Nhược điểm là dễ lỗi thời so với production.

Dynamic data (dữ liệu động). Dữ liệu được sinh ra ngay lúc test chạy — ví dụ mỗi lần test đăng ký, bạn tạo một email mới test_20260627_103045@example.com để tránh trùng. Loại này giúp test độc lập, không đụng nhau, nhưng khó tái hiện lại một bug vì lần sau dữ liệu đã khác.

Production-like data (dữ liệu giống thật). Dữ liệu được sinh ra để trông và hành xử như dữ liệu thật về khối lượng và tính đa dạng, nhưng hoàn toàn giả. Rất quan trọng khi test hiệu năng hoặc test các trường hợp biên mà dữ liệu sạch không có.

Masked/anonymized data (dữ liệu đã che / ẩn danh). Đây là dữ liệu lấy từ production thật nhưng đã được "làm mờ" thông tin nhạy cảm: tên thật đổi thành tên giả, số điện thoại đổi số, số thẻ ngân hàng thay bằng số test. Đây là loại quý nhất vì phản ánh đúng thực tế, nhưng cũng nguy hiểm nhất về mặt pháp lý và bảo mật.

Ba chiến lược tạo test data

Có ba cách chính để có test data, và một tester giỏi biết dùng đúng cách cho đúng tình huống:

  • Tạo thủ công (manual) — gõ tay qua UI hoặc admin panel. Nhanh cho vài case, nhưng không nhân rộng được.
  • Sinh tự động (synthetic generation) — dùng thư viện như Faker để tạo hàng loạt dữ liệu giả hợp lệ. Faker có locale vi_VN sinh được tên Việt như "Nguyễn Văn An", địa chỉ, số điện thoại đúng định dạng.
  • Trích xuất từ production (subsetting + masking) — lấy một tập con từ database thật rồi che dữ liệu nhạy cảm. Dùng khi cần độ chân thực cao, nhất là cho test hiệu năng hoặc test regression phức tạp.

Vấn đề riêng của dữ liệu Việt Nam

Riêng với sản phẩm Việt Nam, test data còn phải cố tình "làm khó" hệ thống: tên có dấu ("Đặng Thị Hồng Nhung"), tên dài, địa chỉ kiểu "Số 12/3A, hẻm 45, Đường Nguyễn Thị Minh Khai", số tiền lớn (hàng chục triệu đồng, cần kiểm tra định dạng phân cách hàng nghìn), số điện thoại nhiều đầu số (03x, 05x, 07x, 08x, 09x). Nếu fixture của bạn chỉ toàn "John Doe" và "0123456789", bạn đang bỏ sót cả một lớp bug.

Tình huống thực tế

Tình huống 1: Sàn thương mại điện tử và "fake pass" đắt giá

Một sàn TMĐT tầm trung ở TP.HCM (gọi là ShopViet) có đội QA 6 người. Họ test tính năng áp mã giảm giá "MIENPHISHIP" — giảm phí vận chuyển cho đơn từ 300.000đ. Trong suốt sprint, mọi test case đều pass. Đội tự tin release.

Ngày đầu ra mắt, hàng loạt khách phàn nàn: mã không áp được cho đơn 305.000đ. Điều tra ra, hóa ra test data của đội QA dùng toàn tài khoản đã được đánh dấu là "khách VIP" trong database (do những tài khoản test này được tạo từ tháng trước và một dev đã set cờ VIP để test tính năng khác). Với khách VIP, hệ thống có luồng tính phí ship riêng, nên mã luôn áp đúng. Còn khách thường — chiếm 95% người dùng thật — lại rơi vào một nhánh code có bug.

Bài học: dữ liệu test bị "nhiễm trạng thái ẩn" (hidden state) mà đội không hề biết. Test pass nhưng là fake pass. Từ sau, ShopViet quy định mỗi bộ test data phải khai báo rõ trạng thái tài khoản (thường/VIP/mới/bị khóa), và có ít nhất một tài khoản "clean baseline" — tài khoản thường, không cờ đặc biệt nào — để test luồng mặc định.

Tình huống 2: Ngân hàng số và bài học masking

Một ví điện tử (giả định tên MoWa) ở Đông Nam Á muốn test tính năng báo cáo giao dịch với dữ liệu thật về khối lượng. Đội DevOps sao chép nguyên một bản database production sang môi trường staging cho đội QA test. Vấn đề: bản copy đó chứa số điện thoại, số CCCD, và lịch sử giao dịch của hơn 2 triệu người dùng thật.

Vài tuần sau, một laptop của cộng tác viên test bị mất. Trên máy có file export dữ liệu để phân tích. Sự cố suýt trở thành khủng hoảng vì đó là dữ liệu cá nhân thật, vi phạm quy định bảo vệ dữ liệu. May mắn phát hiện sớm và xử lý kịp, nhưng đội phải làm lại toàn bộ quy trình.

Giải pháp họ áp dụng sau đó: xây dựng một pipeline masking tự động. Mỗi khi copy dữ liệu từ production, một script sẽ chạy: thay tất cả số điện thoại bằng số giả cùng đầu số, thay tên bằng tên Faker vi_VN, thay số CCCD bằng chuỗi ngẫu nhiên đúng định dạng, và quan trọng — giữ nguyên tính nhất quán tham chiếu (cùng một khách trong bảng giao dịch và bảng tài khoản vẫn map với nhau). Nhờ vậy dữ liệu vẫn "chạy" đúng logic nghiệp vụ mà không lộ ai cả.

Bài học: dữ liệu production chưa masking không bao giờ được rời khỏi vùng kiểm soát. Masking không chỉ là "xóa tên" — nó phải giữ được tính hợp lệ và quan hệ để dữ liệu vẫn dùng test được.

Tình huống 3: Startup edtech và dữ liệu "quá sạch"

Một startup dạy học online (giả định Hocmai+) test chức năng hiển thị tên học viên trên chứng chỉ hoàn thành khóa học. Đội QA test với các tên như "Test User", "Nguyen Van A" — đều pass, chứng chỉ đẹp long lanh.

Khi ra thật, một học viên tên "Nguyễn Đặng Hoàng Phương Uyên" nhận chứng chỉ với tên bị cắt cụt thành "Nguyễn Đặng Hoàng Ph..." vì template chứng chỉ cố định độ rộng. Một học viên khác tên có ký tự "Dž" (do nhập nhầm) làm cả trang render lỗi. Đây là bug thật, khách thật, nhưng test data quá lý tưởng nên không ai bắt được.

Bài học: test data phải chủ động chứa các trường hợp biên xấu — tên dài, dấu tiếng Việt đầy đủ, ký tự Unicode hiếm, chuỗi rỗng, khoảng trắng thừa. Đây là lúc bạn phối hợp TDM với các kỹ thuật như phân tích giá trị biên. Hocmai+ sau đó xây một fixture riêng gọi là "cursed names" — bộ tên độc hại — dùng bắt buộc cho mọi test liên quan hiển thị tên.

Hướng dẫn từng bước

Đây là quy trình quản lý test data mà tôi khuyên bạn áp dụng cho một tính năng bất kỳ:

Bước 1 — Xác định nhu cầu dữ liệu từ test case. Trước khi viết dữ liệu, hãy đọc lại các test case và liệt kê: cần loại tài khoản nào, cần dữ liệu ở trạng thái gì, cần bao nhiêu bản ghi. Ví dụ test giỏ hàng: cần 1 tài khoản trống giỏ, 1 tài khoản giỏ có sẵn 3 sản phẩm, 1 tài khoản giỏ đầy tới giới hạn.

Bước 2 — Chọn chiến lược cho từng loại. Dữ liệu tham chiếu (tỉnh/thành, danh mục) → static fixture. Dữ liệu cần độc lập giữa các lần chạy (email đăng ký) → dynamic. Dữ liệu khối lượng lớn (test hiệu năng) → synthetic hoặc masked production.

Bước 3 — Tạo bộ dữ liệu và đưa vào version control. Fixture nên nằm chung repo với test, dưới dạng file .json/.sql/.csv, có Git theo dõi. Điều này giúp cả đội dùng chung một baseline và tái hiện được bug.

Bước 4 — Thiết lập cơ chế setup và teardown. Trước mỗi lần chạy, seed dữ liệu vào (setup). Sau khi chạy xong, dọn dẹp hoặc reset (teardown). Nguyên tắc vàng: mỗi test nên tự chuẩn bị dữ liệu của mình và không phụ thuộc vào dữ liệu còn sót lại từ test trước.

Bước 5 — Masking nếu dùng dữ liệu thật. Nếu bắt buộc phải lấy từ production, chạy qua pipeline che dữ liệu nhạy cảm trước khi bất kỳ tester nào chạm vào.

Bước 6 — Làm mới định kỳ (refresh). Đặt lịch reset dữ liệu môi trường test (ví dụ mỗi đêm, hoặc mỗi đầu sprint) để chống data decay. Ghi rõ trong tài liệu: dữ liệu này được refresh lúc nào, ai chịu trách nhiệm.

Bước 7 — Ghi tài liệu (data catalog). Duy trì một bảng nhỏ liệt kê: tài khoản test nào, mật khẩu, trạng thái, dùng cho mục đích gì. Điều này cứu bạn khỏi cảnh cả đội hỏi nhau "tài khoản nào test được VNPay vậy?".

Lỗi thường gặp & mẹo

Lỗi 1 — Dùng chung một tài khoản test cho cả đội. Bạn A đang test đổi mật khẩu thì bạn B đăng nhập không được. Mẹo: mỗi người/mỗi luồng có tài khoản riêng, hoặc sinh động lúc chạy.

Lỗi 2 — Hardcode dữ liệu trong test. Nhét thẳng ID sản phẩm product_id = 4521 vào test. Đến khi database refresh, ID đó không còn, test fail hàng loạt. Mẹo: tham chiếu qua fixture hoặc tra cứu động theo thuộc tính (ví dụ "sản phẩm đầu tiên còn hàng") thay vì ID cứng.

Lỗi 3 — Dữ liệu quá sạch, quá lý tưởng. Như tình huống 3. Mẹo: luôn có một fixture "dữ liệu bẩn" cố tình chứa case biên.

Lỗi 4 — Không teardown, để dữ liệu rác tích tụ. Sau vài trăm lần chạy test đăng ký, database đầy hàng nghìn tài khoản rác làm chậm cả môi trường. Mẹo: teardown sau mỗi lần chạy, hoặc dùng transaction rollback.

Lỗi 5 — Copy production về mà quên masking. Rủi ro pháp lý và mất uy tín, như tình huống 2. Mẹo: coi masking là bước bắt buộc, không thương lượng.

Mẹo nâng cao: với dữ liệu tiền tệ và ngày tháng, hãy chuẩn bị sẵn các giá trị "độc": số tiền 0đ, số âm, số cực lớn; ngày 29/02 năm nhuận, ngày cuối tháng, timezone khác nhau. Những giá trị này bắt được rất nhiều bug ẩn.

Bài tập thực hành

Bài 1 — Phân loại. Cho tính năng "đăng ký thành viên và nhận voucher chào mừng", hãy liệt kê tất cả test data cần thiết và phân loại chúng vào 4 loại (static / dynamic / production-like / masked). Giải thích vì sao email đăng ký nên là dynamic.

Bài 2 — Thiết kế fixture bẩn. Viết một file JSON chứa 8 bộ tên khách hàng "độc hại" để test hiển thị tên trên hóa đơn của một app Việt Nam. Bao gồm: tên dài trên 50 ký tự, tên đủ dấu tiếng Việt, tên có ký tự Unicode hiếm, tên chỉ có khoảng trắng, tên rỗng.

Bài 3 — Thiết kế masking. Bạn được giao một bảng customers có các cột: full_name, phone, cccd, email, balance. Hãy mô tả quy tắc masking cho từng cột, đảm bảo dữ liệu sau masking vẫn hợp lệ về định dạng và vẫn map nhất quán giữa các bảng liên quan.

Bài 4 — Truy vết một fake pass. Đọc lại tình huống 1. Nếu bạn là tester của ShopViet, hãy đề xuất 3 biện pháp cụ thể trong quy trình TDM để ngăn loại lỗi "trạng thái ẩn" đó tái diễn.

Tóm tắt

Test Data Management là nền móng thầm lặng của mọi hoạt động kiểm thử. Dữ liệu tốt giúp test của bạn nói lên sự thật; dữ liệu tệ khiến test nói dối — pass giả hoặc fail giả, cả hai đều nguy hiểm. Hãy nhớ bốn loại dữ liệu (static, dynamic, production-like, masked) và biết chọn đúng loại cho đúng tình huống. Luôn quản lý trạng thái và quan hệ của dữ liệu, đừng để "trạng thái ẩn" đánh lừa. Cố tình chuẩn bị dữ liệu "bẩn" với các case biên, đặc biệt là dữ liệu tiếng Việt có dấu, tên dài, và tiền tệ. Đưa fixture vào version control, thiết lập setup/teardown, làm mới định kỳ, và tuyệt đối masking dữ liệu thật trước khi dùng. Cuối cùng, duy trì một data catalog để cả đội không phải "mò" tài khoản test. Làm chủ được dữ liệu, bạn đã làm chủ được một nửa chất lượng của công việc kiểm thử.