Trong thế giới phát triển phần mềm, rất ít chủ đề có thể khơi dậy cuộc tranh luận sôi nổi như giá trị của kiểm thử tự động. Trong khi một số nhà phát triển tin tưởng tuyệt đối vào Phát Triển Hướng Kiểm Thử (TDD) và bộ kiểm thử toàn diện, thì số khác lại xem chúng như một sự lãng phí thời gian khổng lồ. Sự chia rẽ này gần đây đã được nêu bật trong một cuộc thảo luận trực tuyến sôi nổi, nơi các nhà phát triển chia sẻ những kinh nghiệm trái ngược nhau từ thực tế. Cuộc trò chuyện tiết lộ một mâu thuẫn sâu sắc giữa các phương pháp hay nhất về lý thuyết và thực tế phức tạp của việc xuất bản mã nguồn.
Lập Luận Chống Lại Kiểm Thử
Một bộ phận đáng kể trong cộng đồng nhà phát triển vẫn tỏ ra hoài nghi sâu sắc về lợi tức đầu tư của kiểm thử tự động. Một nhà phát triển kỳ cựu với gần 20 năm kinh nghiệm đã bày tỏ một quan điểm được nhiều người đồng tình, khẳng định rằng họ chưa bao giờ, dù chỉ một lần, thấy việc kiểm thử tự động xứng đáng với lượng thời gian khổng lồ mà nó làm lãng phí. Góc nhìn này thường đến từ những người đã trải qua việc bảo trì các bài kiểm thử dễ vỡ, được thiết kế kém, thường xuyên bị lỗi với mọi thay đổi mã nguồn nhỏ. Lời chỉ trích đặc biệt gay gắt đối với kiểm thử giao diện người dùng (UI), vốn nổi tiếng là không ổn định và tốn nhiều thời gian để bảo trì. Đối với những nhà phát triển này, chi phí để viết và bảo trì các bài kiểm thử đơn giản là không biện minh được cho những lợi ích mà họ nhận thấy, khiến họ đặt câu hỏi về một trong những con bò thần thiêng liêng nhất của kỹ thuật phần mềm hiện đại.
Các Lập Luận trong Cuộc Tranh Luận về Testing
Ủng Hộ Testing:
- Phát hiện lỗi hồi quy trong quá trình refactoring
- Đóng vai trò như tài liệu thực thi được
- Cải thiện thiết kế code bằng cách khuyến khích sự đơn giản
- Xác định các trường hợp biên trong quá trình phát triển
- Mang lại sự tự tin cho các thay đổi phức tạp
Phản Đối Testing:
- Chi phí bảo trì cao cho các test dễ hỏng
- Thời gian đầu tư không luôn xứng đáng với lợi ích
- Có thể tạo ra sự tự tin sai lầm nếu viết kém
- Có thể test implementation thay vì behavior
- UI test đặc biệt không ổn định và tốn kém
Sự Bảo Vệ Thực Tế Cho Kiểm Thử
Ở phía bên kia của cuộc tranh luận, nhiều nhà phát triển đã đưa ra những ví dụ cụ thể và thuyết phục về giá trị thực tiễn của kiểm thử. Một nhà phát triển chia sẻ cách các bài kiểm thử đóng vai trò quan trọng trong quá trình tái cấu trúc một công cụ xây dựng truy vấn SQL, ngay lập tức báo hiệu rằng các mệnh đề JOIN đang thiếu điều kiện ON. Loại phản hồi tức thời này là vô giá trong các hệ thống phức tạp. Một người khác lưu ý rằng việc viết mã với tư duy về kiểm thử một cách tự nhiên sẽ dẫn đến các thiết kế đơn giản và dễ bảo trì hơn, bởi các hàm làm quá nhiều việc hoặc có nhiều tác dụng phụ vốn nổi tiếng là khó kiểm thử. Lập luận thuyết phục nhất đến từ những người sử dụng kiểm thử như một công cụ thiết kế, với một nhà phát triển cho biết rằng khoảng ba đến năm lần một năm, các bài kiểm thử giúp tôi làm cho một tính năng trở nên hữu ích hơn rất nhiều vì tôi nhận ra rằng có một trường hợp đặc biệt thú vị mà rất dễ kiểm tra và dễ dàng triển khai.
Tôi đưa thẳng mã nguồn đã được sửa đổi cực kỳ phức tạp vào môi trường sản xuất và đã không gặp phải một lỗi sản xuất nào trong hơn 6 năm. Lý do chính là nhờ vào các bài kiểm thử tự động.
Phổ Kiểm Thử và Khoảng Cách Kỹ Năng
Cuộc thảo luận tiết lộ rằng kiểm thử không phải là một lựa chọn nhị phân mà tồn tại trên một phổ về chất lượng và hiệu quả. Như một bình luận viên sắc sảo nhận xét, có một cuộc chiến ba phe trong kiểm thử giữa những người nghĩ rằng chúng thật khủng khiếp và viết ra những bài kiểm thử trở thành lời tiên tri tự ứng nghiệm, những người nghĩ rằng các bài kiểm thử tệ không phải là xấu và các bài kiểm thử tốt thì 'tốn quá nhiều công sức', và một số ít người nghĩ rằng các bài kiểm thử khác nhau chỉ đơn giản là những công việc khác nhau. Điều này cho thấy vấn đề có lẽ không nằm ở bản thân việc kiểm thử, mà là ở một khoảng cách kỹ năng phổ biến trong việc viết các bài kiểm thử có giá trị. Nhiều nhà phát triển nhấn mạnh rằng học cách viết các bài kiểm thử hiệu quả đòi hỏi sự hướng dẫn và thực hành, với một người chia sẻ rằng họ cần sự hướng dẫn từ nhiều người cố vấn để cảm thấy thành thạo. Nghệ thuật nằm ở chỗ tạo ra các bài kiểm thử kinh tế và bao phủ các tính năng cốt lõi mang lại giá trị cho doanh nghiệp, lý tưởng nhất là ở mức thô thiển nhất có thể.
Các Loại Kiểm Thử Phổ Biến và Mục Đích Của Chúng
- Unit Tests: Xác minh các thành phần hoặc hàm riêng lẻ một cách độc lập. Đặc biệt có giá trị đối với các thuật toán phức tạp và như một tài liệu thực thi.
- Integration Tests: Xác minh rằng nhiều thành phần hoạt động cùng nhau một cách chính xác. Thiết yếu cho các quy trình làm việc quan trọng và hành vi của hệ thống.
- UI/E2E Tests: Kiểm thử các quy trình làm việc hoàn chỉnh của người dùng thông qua giao diện. Có thể phát hiện các vấn đề về bố cục đặc thủ của trình duyệt/thiết bị nhưng thường không ổn định và tốn kém để duy trì.
- Regression Tests: Nhắm mục tiêu cụ thể vào các lỗi đã được sửa trước đó để ngăn chặn tái phát. Được đánh giá rộng rãi là mang lại lợi tức đầu tư rõ ràng nhất.
- Exploratory Testing: Kiểm thử thủ công để xác thực các đặc tả so với yêu cầu thực tế và khám phá các hành vi không mong đợi.
Giải Pháp Thay Thế Bằng Xác Minh Hình Thức
Vượt ra ngoài cuộc tranh luận về kiểm thử, một số nhà phát triển chỉ ra các phương pháp nghiêm ngặt hơn để đảm bảo tính đúng đắn của mã nguồn. Bài viết gốc đã thảo luận về Phát Triển Hướng Chứng Minh (Proof-Driven Development) và giá trị kinh doanh của mã sạch giúp dễ dàng lý giải hơn. Các bình luận viên đã mở rộng điều này bằng cách thảo luận về khả năng lý thuyết của xác minh hình thức—việc chứng minh tính đúng đắn của một chương trình bằng toán học. Tuy nhiên, họ nhanh chóng chỉ ra những hạn chế thực tế: việc chứng minh tính đúng đắn sẽ đòi hỏi phải xác minh không chỉ mã nguồn của bạn, mà còn mọi phụ thuộc, trình biên dịch, thư viện chuẩn, và thậm chí cả kiến trúc tập lệnh của bộ xử lý. Xét đến việc trong thực tế đã phát hiện ra lỗi trong các bộ xử lý lớn như kiến trúc RDRAND và Skylake của Intel, phương pháp này phần lớn vẫn mang tính lý thuyết đối với hầu hết các ứng dụng thực tế, mặc dù nó làm nổi bật thách thức cơ bản trong việc đạt được sự chắc chắn tuyệt đối trong các hệ thống phức tạp.
Tìm Điểm Chung
Hầu hết các nhà phát triển có kinh nghiệm cuối cùng đều tìm ra một cách tiếp cận cân bằng phù hợp với ngữ cảnh cụ thể của họ. Sự đồng thuận cho thấy rằng các bài kiểm thử hồi quy—các bài kiểm thử được viết để ngăn chặn các lỗi đã được sửa trước đó tái diễn—mang lại giá trị rõ ràng một cách nhất quán. Như một nhà phát triển nhận xét, Theo kinh nghiệm của tôi, trong tất cả các loại kiểm thử mà người ta có thể viết, dễ dàng nhất để thấy rằng các bài kiểm thử hồi quy tự chứng minh được giá trị của chúng. Điều then chốt là một chiến lược kiểm thử được suy nghĩ thấu đáo hơn là việc tuân thủ một cách giáo điều bất kỳ phương pháp luận đơn lẻ nào. Các loại kiểm thử khác nhau phục vụ các mục đích khác nhau: kiểm thử đơn vị cho các thuật toán phức tạp, kiểm thử tích hợp cho các quy trình làm việc quan trọng, và kiểm thử thủ công thăm dò cẩn thận để xác thực các đặc tả so với các yêu cầu thực tế. Các nhóm thành công nhất dường như là những nhóm coi kiểm thử như một công cụ thực tiễn hơn là một giáo lý, tập trung vào các bài kiểm thử mang lại sự tự tin thực sự mà không tạo ra gánh nặng bảo trì.
Cuộc tranh luận về kiểm thử cuối cùng phản ánh thách thức rộng lớn hơn của kỹ thuật phần mềm: cân bằng giữa các thực hành lý tưởng và các ràng buộc thực tế. Trong khi kiểm thử tự động có thể mang lại lợi ích đáng kể trong việc phát hiện các lỗi hồi quy, cho phép tái cấu trúc, và thậm chí cải thiện thiết kế, thì các phương pháp kiểm thử kém thực sự có thể trở thành một gánh nặng tốn kém. Cách tiếp cận thành công nhất dường như là một cách tiếp cận thực tế—đầu tư vào các bài kiểm thử mang lại giá trị rõ ràng trong khi tránh việc tuân thủ một cách giáo điều việc kiểm thử chỉ vì mục đích kiểm thử. Như với hầu hết các quyết định kỹ thuật, ngữ cảnh là quan trọng, và chiến lược kiểm thử phù hợp phụ thuộc vào nhu cầu cụ thể của dự án, nhóm và tổ chức.
Tham khảo: Proof-Driven Development (or- the business value of Clean Code)