Tôi nên đơn vị kiểm tra các lớp con của tôi hoặc lớp cha trừu tượng của tôi?


12

Tôi có một triển khai bộ xương, như trong Mục 18 từ Java hiệu quả (thảo luận mở rộng ở đây ). Đây là một lớp trừu tượng cung cấp 2 phương thức công khai phương thứcA () và phương thứcB () gọi các phương thức lớp con để "lấp đầy các khoảng trống" mà tôi không thể định nghĩa theo cách trừu tượng hóa.

Tôi đã phát triển nó đầu tiên bằng cách tạo ra một lớp cụ thể và viết các bài kiểm tra đơn vị cho nó. Khi lớp thứ hai đến, tôi có thể trích xuất hành vi chung, thực hiện "các khoảng trống bị thiếu" trong lớp thứ hai và nó đã sẵn sàng (tất nhiên, các bài kiểm tra đơn vị đã được tạo cho lớp con thứ hai).

Thời gian trôi qua và bây giờ tôi có 4 lớp con, mỗi lớp thực hiện 3 phương thức được bảo vệ ngắn rất cụ thể để thực hiện cụ thể của chúng, trong khi việc thực hiện bộ xương thực hiện tất cả các công việc chung.

Vấn đề của tôi là khi tôi tạo một triển khai mới, tôi viết lại các bài kiểm tra:

  • Liệu lớp con gọi một phương thức cần thiết nhất định?
  • Liệu một phương thức nhất định có một chú thích nhất định?
  • Tôi có nhận được kết quả mong đợi từ phương pháp A không?
  • Tôi có nhận được kết quả mong đợi từ phương pháp B không?

Trong khi thấy lợi thế với phương pháp này:

  • Nó ghi lại các yêu cầu của lớp con thông qua các bài kiểm tra
  • Nó có thể thất bại nhanh trong trường hợp tái cấu trúc có vấn đề
  • Kiểm tra toàn bộ lớp con và thông qua API công khai của chúng ("phương thứcA () có hoạt động không?" Và không "phương thức được bảo vệ này có hoạt động không?")

Vấn đề tôi gặp phải là các bài kiểm tra cho một lớp con mới về cơ bản là không có trí tuệ: - Các bài kiểm tra đều giống nhau trong tất cả các lớp con, chúng chỉ thay đổi kiểu trả về của các phương thức (triển khai bộ xương là chung) và các thuộc tính I kiểm tra phần khẳng định của bài kiểm tra - Thông thường các lớp con không có bài kiểm tra dành riêng cho chúng

Tôi thích cách các bài kiểm tra tập trung vào kết quả của lớp con và bảo vệ nó khỏi tái cấu trúc, nhưng thực tế việc thực hiện bài kiểm tra chỉ là "công việc thủ công" khiến tôi nghĩ rằng mình đang làm gì đó sai.

Là vấn đề phổ biến khi kiểm tra phân cấp lớp? Làm thế nào tôi có thể tránh điều đó?

ps: Tôi đã nghĩ về việc thử nghiệm lớp bộ xương, nhưng có vẻ lạ khi tạo ra một bản mô phỏng của một lớp trừu tượng để có thể kiểm tra nó. Và tôi nghĩ rằng bất kỳ tái cấu trúc nào trên lớp trừu tượng thay đổi hành vi mà lớp con không mong đợi sẽ không được chú ý nhanh như vậy. Ruột của tôi nói với tôi rằng kiểm tra lớp con "nói chung" là cách tiếp cận ưa thích ở đây, nhưng xin vui lòng cho tôi biết tôi sai :)

ps2: Tôi đã googled và tìm thấy nhiều câu hỏi về chủ đề này. Một trong số đó là một trong những này trong đó có một câu trả lời rất lớn từ Nigel Thorne, trường hợp của tôi sẽ là "số 1" của mình Điều đó sẽ rất tuyệt, nhưng tôi không thể tái cấu trúc vào thời điểm này, vì vậy tôi sẽ phải sống với vấn đề này. Nếu tôi có thể cấu trúc lại, tôi sẽ có mỗi lớp con làm chiến lược. Điều đó sẽ ổn, nhưng tôi vẫn sẽ kiểm tra "lớp chính" và kiểm tra các chiến lược, nhưng tôi sẽ không nhận thấy bất kỳ sự tái cấu trúc nào phá vỡ sự tích hợp giữa lớp chính và chiến lược.

ps3: Tôi đã tìm thấy một số câu trả lời nói rằng "có thể chấp nhận được" để kiểm tra lớp trừu tượng. Tôi đồng ý rằng điều này có thể chấp nhận được, nhưng tôi muốn biết đó là cách tiếp cận ưa thích trong trường hợp này (tôi vẫn đang bắt đầu với các bài kiểm tra đơn vị)


2
Viết một lớp kiểm tra trừu tượng và có các bài kiểm tra cụ thể của bạn kế thừa từ nó, phản ánh cấu trúc của mã doanh nghiệp. Các thử nghiệm được cho là để kiểm tra hành vi chứ không phải việc thực hiện một đơn vị, nhưng điều đó không có nghĩa là bạn không thể sử dụng kiến ​​thức nội bộ của mình về hệ thống để đạt được mục tiêu đó hiệu quả hơn.
Kilian Foth

Tôi đã đọc ở đâu đó rằng người ta không nên sử dụng tính kế thừa trong các bài kiểm tra, tôi đang tìm nguồn để đọc nó một cách cẩn thận
JSBach

4
@KilianFoth bạn có chắc về lời khuyên này không? Điều này nghe có vẻ như một công thức cho các bài kiểm tra đơn vị giòn, rất nhạy cảm với những thay đổi thiết kế và do đó không thể duy trì được.
Konrad Morawski

Câu trả lời:


5

Tôi không thể thấy cách bạn viết bài kiểm tra cho một lớp cơ sở trừu tượng ; bạn không thể khởi tạo nó, vì vậy bạn không thể có một phiên bản của nó để kiểm tra. Bạn có thể tạo một "lớp giả", lớp con cụ thể chỉ với mục đích thử nghiệm nó - không chắc chắn mức độ sử dụng của nó. YMMV.

Mỗi khi bạn tạo một triển khai mới (lớp), thì bạn nên viết các bài kiểm tra thực hiện việc thực hiện mới đó. Vì các phần của chức năng ("khoảng trống" của bạn) được triển khai trong mỗi lớp con, điều này là hoàn toàn cần thiết; đầu ra của mỗi phương thức được kế thừa có thể (và có lẽ nên ) khác nhau cho mỗi lần thực hiện mới.


Vâng, chúng khác nhau (các loại và nội dung là khác nhau). Về mặt kỹ thuật, tôi sẽ có thể chế nhạo lớp này hoặc chỉ thực hiện đơn giản cho mục đích thử nghiệm với các triển khai trống. Tôi không thích cách tiếp cận này. Nhưng việc tôi không "cần" nghĩ để vượt qua các bài kiểm tra trong các triển khai mới khiến tôi cảm thấy kỳ lạ và cũng khiến tôi đặt câu hỏi về việc tôi tự tin như thế nào trong bài kiểm tra này (tất nhiên, nếu tôi thay đổi mục đích của lớp cơ sở, các thử nghiệm thất bại, đó là một bằng chứng cho thấy tôi có thể tin tưởng chúng)
JSBach

4

Thông thường, bạn sẽ tạo một lớp cơ sở để thực thi một giao diện. Bạn muốn thử nghiệm giao diện đó, không phải chi tiết bên dưới. Do đó, bạn nên tạo các bài kiểm tra khởi tạo từng lớp riêng lẻ nhưng chỉ kiểm tra thông qua các phương thức của lớp cơ sở.

Ưu điểm của phương pháp này là vì bạn đã thử nghiệm giao diện, giờ đây bạn có thể cấu trúc lại bên dưới giao diện. Bạn có thể thấy mã đó trong một lớp con nên nằm trong cha mẹ hoặc ngược lại. Bây giờ các thử nghiệm của bạn sẽ chứng minh rằng bạn đã không phá vỡ hành vi khi bạn di chuyển mã đó.

Nói chung, bạn nên kiểm tra mã xem nó dự định sẽ được sử dụng như thế nào. Điều đó có nghĩa là tránh thử nghiệm các phương thức riêng tư và thường có nghĩa là đơn vị của bạn đang thử nghiệm có thể lớn hơn một chút so với bạn nghĩ ban đầu - có lẽ là một nhóm các lớp thay vì một lớp duy nhất. Mục tiêu của bạn là cô lập các thay đổi để bạn hiếm khi phải thay đổi kiểm tra khi bạn cấu trúc lại trong một phạm vi nhất định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.