Tôi đang làm việc trên một dự án mà chúng tôi phải thực hiện và thử nghiệm một số mô-đun mới. Tôi có một kiến trúc khá rõ ràng trong đầu nên tôi đã nhanh chóng viết ra các lớp và phương thức chính và sau đó chúng tôi bắt đầu viết các bài kiểm tra đơn vị.
Trong khi viết các bài kiểm tra, chúng tôi đã phải thực hiện một vài sửa đổi cho mã gốc, chẳng hạn như
- Công khai các phương thức riêng tư để kiểm tra chúng
- Thêm phương thức bổ sung để truy cập các biến riêng tư
- Thêm các phương thức bổ sung để tiêm các đối tượng giả nên được sử dụng khi mã chạy bên trong một bài kiểm tra đơn vị.
Bằng cách nào đó tôi có cảm giác rằng đây là những triệu chứng mà chúng ta đang làm sai, ví dụ
- thiết kế ban đầu đã sai (một số chức năng nên được công khai ngay từ đầu),
- mã không được thiết kế đúng để được giao tiếp với các bài kiểm tra đơn vị (có thể do thực tế là chúng tôi đã bắt đầu thiết kế các bài kiểm tra đơn vị khi đã có một vài lớp được thiết kế),
- chúng tôi đang triển khai kiểm tra đơn vị sai cách (ví dụ: kiểm tra đơn vị chỉ nên kiểm tra trực tiếp / giải quyết các phương thức công khai của API, không phải phương thức riêng tư),
- một hỗn hợp của ba điểm trên và có thể một số vấn đề bổ sung mà tôi chưa nghĩ đến.
Vì tôi có một số kinh nghiệm về kiểm thử đơn vị nhưng tôi không phải là một bậc thầy, tôi sẽ rất thích đọc suy nghĩ của bạn về những vấn đề này.
Bên cạnh các câu hỏi chung ở trên, tôi có một số câu hỏi kỹ thuật cụ thể hơn:
Câu hỏi 1. Có ý nghĩa gì khi trực tiếp kiểm tra một phương thức riêng m của lớp A và thậm chí công khai nó để kiểm tra nó không? Hoặc tôi nên cho rằng m được kiểm tra gián tiếp bằng các bài kiểm tra đơn vị bao gồm các phương thức công khai khác gọi cho m?
Câu hỏi 2. Nếu một thể hiện của lớp A chứa một thể hiện của lớp B (tập hợp tổng hợp), nó có hợp lý để giả định B để kiểm tra A không? Ý tưởng đầu tiên của tôi là tôi không nên chế giễu B vì thể hiện B là một phần của thể hiện A, nhưng sau đó tôi bắt đầu nghi ngờ về điều này. Đối số của tôi chống lại việc chế nhạo B cũng giống như đối với 1: B là wrt riêng tư A và chỉ được sử dụng để thực hiện nó, do đó, chế giễu B có vẻ như tôi đang tiết lộ các chi tiết riêng tư của A như trong (1). Nhưng có lẽ những vấn đề này cho thấy một lỗ hổng thiết kế: có thể chúng ta không nên sử dụng kết hợp tổng hợp mà là một liên kết đơn giản từ A đến B.
Câu hỏi 3. Trong ví dụ trên, nếu chúng ta quyết định giả định B, làm thế nào để chúng ta tiêm cá thể B vào A? Dưới đây là một số ý tưởng chúng tôi đã có:
- Đặt đối tượng B làm đối số cho hàm tạo A thay vì tạo đối tượng B trong hàm tạo A.
- Truyền giao diện BFactory làm đối số cho hàm tạo A và cho phép A sử dụng nhà máy để tạo cá thể B riêng của nó.
- Sử dụng một đơn vị BFactory là riêng tư để A. Sử dụng phương thức tĩnh A :: setBFactory () để đặt đơn vị. Khi A muốn tạo cá thể B, nó sử dụng singleton của nhà máy nếu nó được đặt (kịch bản thử nghiệm), nó tạo B trực tiếp nếu singleton không được đặt (kịch bản mã sản xuất).
Hai lựa chọn đầu tiên có vẻ sạch hơn đối với tôi, nhưng chúng yêu cầu thay đổi chữ ký của nhà xây dựng A: thay đổi API chỉ để làm cho nó dễ kiểm tra hơn có vẻ khó xử với tôi, đây có phải là một thông lệ không?
Cái thứ ba có một ưu điểm là nó không yêu cầu thay đổi chữ ký của hàm tạo (thay đổi API ít xâm lấn hơn), nhưng nó yêu cầu gọi phương thức tĩnh setBFactory () trước khi bắt đầu thử nghiệm, dễ bị lỗi IMO ( phụ thuộc ngầm vào một cuộc gọi phương thức để các thử nghiệm hoạt động đúng). Vì vậy, tôi không biết chúng ta nên chọn cái nào.