Mọi thứ đều có giao diện. Khi tôi đội chiếc mũ thử nghiệm của mình, tôi sử dụng một thế giới quan cụ thể để viết một bài kiểm tra:
- Nếu một cái gì đó tồn tại, nó có thể được đo.
- Nếu nó không thể được đo, nó không thành vấn đề. Nếu nó thành vấn đề, tôi chưa tìm ra cách nào để đo nó cả.
- Yêu cầu quy định các thuộc tính có thể đo lường được, hoặc chúng là vô dụng.
- Một hệ thống đáp ứng một yêu cầu khi nó chuyển từ trạng thái không mong đợi sang trạng thái dự kiến được quy định bởi yêu cầu.
- Một hệ thống bao gồm các thành phần tương tác, có thể là các hệ thống con. Một hệ thống là chính xác khi tất cả các thành phần là chính xác và sự tương tác giữa các thành phần là chính xác.
Trong trường hợp của bạn, hệ thống của bạn có ba phần chính:
- một số loại dữ liệu hoặc hình ảnh, có thể được khởi tạo từ các tệp
- một cơ chế hiển thị dữ liệu
- một cơ chế để sửa đổi dữ liệu
Ngẫu nhiên, điều đó nghe rất giống kiến trúc Model-View-Controller ban đầu đối với tôi. Lý tưởng nhất, ba yếu tố này thể hiện khớp nối lỏng lẻo - nghĩa là, bạn xác định ranh giới rõ ràng giữa chúng với các giao diện được xác định rõ (và do đó có thể kiểm tra tốt).
Một tương tác phức tạp với phần mềm có thể được dịch thành các bước nhỏ có thể được thực hiện theo các yếu tố của hệ thống mà chúng tôi đang thử nghiệm. Ví dụ:
Tôi tải một tập tin với một số dữ liệu. Nó hiển thị một biểu đồ. Khi tôi kéo một thanh trượt trong giao diện người dùng, biểu đồ sẽ trở nên chao đảo.
Điều này dường như dễ dàng để kiểm tra thủ công và khó kiểm tra tự động. Nhưng hãy dịch câu chuyện đó vào hệ thống của chúng tôi:
- UI cung cấp một cơ chế để mở tệp: Bộ điều khiển là chính xác.
- Khi tôi mở một tệp, Bộ điều khiển đưa ra một lệnh thích hợp cho Mô hình: Tương tác Mô hình Bộ điều khiển là chính xác.
- Đưa ra một tệp thử nghiệm, mô hình phân tích cú pháp này vào cấu trúc dữ liệu dự kiến: Mô hình là chính xác.
- Đưa ra cấu trúc dữ liệu thử nghiệm, Chế độ xem hiển thị đầu ra dự kiến: Chế độ xem là chính xác. Một số cấu trúc dữ liệu thử nghiệm sẽ là đồ thị bình thường, một số khác sẽ là đồ thị lung lay.
- Mô hình View tương tác là chính xác
- Giao diện người dùng cung cấp một thanh trượt để làm cho biểu đồ chao đảo: Bộ điều khiển là chính xác.
- Khi thanh trượt được đặt thành một giá trị cụ thể, Bộ điều khiển sẽ đưa ra lệnh mong đợi cho Mô hình: Tương tác Mô hình Bộ điều khiển là chính xác.
- Khi nhận được lệnh kiểm tra liên quan đến độ chao đảo, Mô hình sẽ chuyển đổi cấu trúc dữ liệu thử nghiệm thành cấu trúc dữ liệu kết quả dự kiến.
Được nhóm theo thành phần, chúng tôi kết thúc với các thuộc tính sau để kiểm tra:
- Mô hình:
- phân tích cú pháp tập tin
- đáp ứng với lệnh mở tệp
- cung cấp quyền truy cập vào dữ liệu
- đáp ứng với lệnh make-wobbly
- Lượt xem:
- Điều khiển:
- cung cấp quy trình mở tệp
- vấn đề mở tệp
- cung cấp quy trình làm việc lung lay
- vấn đề lệnh make-wobbly
- Toàn bộ hệ thống:
- kết nối giữa các thành phần là chính xác.
Nếu chúng ta không phân tách vấn đề kiểm tra thành các bài kiểm tra nhỏ hơn, việc kiểm tra trở nên thực sự khó khăn và thực sự mong manh. Câu chuyện trên cũng có thể được triển khai như là khi tôi tải một tệp cụ thể và đặt thanh trượt thành một giá trị cụ thể, một hình ảnh cụ thể được hiển thị. Điều này là dễ vỡ vì nó bị hỏng khi bất kỳ yếu tố nào trong hệ thống thay đổi.
- Nó bị vỡ khi tôi thay đổi các điều khiển cho sự chao đảo (ví dụ: xử lý trên biểu đồ thay vì một thanh trượt trong bảng điều khiển).
- Nó bị vỡ khi tôi thay đổi định dạng đầu ra (ví dụ: bitmap được hiển thị khác vì tôi đã thay đổi màu mặc định của biểu đồ hoặc vì tôi đã thêm khử răng cưa để làm cho biểu đồ trông mượt mà hơn. Lưu ý rằng trong cả hai trường hợp này).
Các thử nghiệm dạng hạt cũng có lợi thế thực sự lớn khi chúng cho phép tôi phát triển hệ thống mà không sợ phá vỡ bất kỳ tính năng nào. Vì tất cả các hành vi cần thiết được đo bằng một bộ kiểm tra hoàn chỉnh, các bài kiểm tra sẽ thông báo cho tôi nếu có bất cứ điều gì phá vỡ. Vì chúng là dạng hạt, chúng sẽ chỉ cho tôi khu vực có vấn đề. Ví dụ: nếu tôi vô tình thay đổi giao diện của bất kỳ thành phần nào, chỉ có các thử nghiệm của giao diện đó sẽ thất bại và không có thử nghiệm nào khác xảy ra khi sử dụng gián tiếp giao diện đó.
Nếu thử nghiệm được cho là dễ dàng, điều này đòi hỏi một thiết kế phù hợp. Ví dụ, có vấn đề khi tôi kết nối các thành phần cứng trong hệ thống: nếu tôi muốn kiểm tra sự tương tác của một thành phần với các thành phần khác trong hệ thống, tôi cần thay thế các thành phần khác đó bằng các sơ khai kiểm tra để tôi đăng nhập, xác minh, và biên đạo mà tương tác. Nói cách khác, tôi cần một số cơ chế tiêm phụ thuộc, và nên tránh phụ thuộc tĩnh. Khi kiểm tra giao diện người dùng, sẽ rất hữu ích khi giao diện người dùng này có thể viết được.
Tất nhiên, hầu hết đó chỉ là ảo mộng về một thế giới lý tưởng, nơi mọi thứ đều tách rời và dễ dàng kiểm chứng và bay kỳ lân lan truyền tình yêu và hòa bình ;-) Trong khi mọi thứ về cơ bản đều có thể kiểm chứng, thì thường rất khó để làm điều đó, và bạn tốt hơn sử dụng thời gian của bạn. Tuy nhiên, các hệ thống có thể được thiết kế để kiểm tra và thông thường, ngay cả các hệ thống kiểm tra không xác định có các API hoặc hợp đồng nội bộ có thể được kiểm tra (nếu không, tôi cá là kiến trúc của bạn là rác rưởi và bạn đã viết một quả bóng lớn). Theo kinh nghiệm của tôi, ngay cả một lượng nhỏ thử nghiệm (tự động) cũng làm tăng đáng kể chất lượng.