Làm thế nào để tránh sự cần thiết phải kiểm tra đơn vị phương pháp riêng tư


15

Tôi biết bạn không cần phải thử nghiệm các phương thức riêng tư và nếu có vẻ như bạn cần, có thể có một lớp học đang chờ để xuất hiện.

Nhưng, tôi không muốn có một lớp học chỉ để tôi có thể kiểm tra các giao diện công cộng của chúng và tôi thấy rằng đối với nhiều lớp nếu tôi chỉ kiểm tra các phương thức công khai thì cuối cùng tôi phải chế giễu rất nhiều phụ thuộc và các bài kiểm tra đơn vị là to lớn và khó theo dõi

Tôi rất thích chế giễu các phương thức riêng tư khi kiểm tra các phương thức công khai và chế giễu các phụ thuộc bên ngoài khi kiểm tra các phương thức riêng tư.

Tôi có điên không?


Một bài kiểm tra đơn vị kỹ lưỡng nên ngầm bao gồm tất cả các thành viên riêng của một lớp nhất định, bởi vì trong khi bạn không thể gọi họ trực tiếp, hành vi của họ vẫn sẽ có ảnh hưởng đến đầu ra. Nếu họ không thì tại sao họ lại ở đó ngay từ đầu? Hãy nhớ trong kiểm tra đơn vị những gì bạn quan tâm là kết quả, chứ không phải làm thế nào kết quả được đưa ra.
GordonM

Câu trả lời:


23

Bạn đúng một phần - bạn không nên trực tiếp kiểm tra các phương pháp riêng tư. Các phương thức riêng tư trên một lớp nên được gọi bằng một hoặc nhiều phương thức công khai (có thể gián tiếp - một phương thức riêng được gọi bằng phương thức công khai có thể gọi các phương thức riêng tư khác). Do đó, khi kiểm tra các phương thức công khai của bạn, bạn cũng sẽ kiểm tra các phương thức riêng tư của mình. Nếu bạn có các phương thức riêng vẫn chưa được kiểm tra, các trường hợp kiểm tra của bạn không đủ hoặc các phương thức riêng không được sử dụng và có thể được gỡ bỏ.

Nếu bạn đang thực hiện một phương pháp thử nghiệm hộp trắng, bạn nên xem xét chi tiết triển khai các phương thức riêng tư của mình khi xây dựng các thử nghiệm đơn vị xung quanh các phương thức công khai của bạn. Nếu bạn đang thực hiện một cách tiếp cận hộp đen, bạn không nên thử nghiệm bất kỳ chi tiết triển khai nào theo phương pháp công khai hoặc riêng tư mà chống lại hành vi dự kiến.

Cá nhân, tôi thích cách tiếp cận hộp trắng cho các bài kiểm tra đơn vị. Tôi có thể tạo các thử nghiệm để đưa các phương thức và các lớp đang thử nghiệm vào các trạng thái khác nhau gây ra hành vi thú vị trong các phương thức công khai và riêng tư của tôi và sau đó khẳng định rằng kết quả là những gì tôi mong đợi.

Vì vậy - đừng chế giễu phương pháp riêng tư của bạn. Sử dụng chúng để hiểu những gì bạn cần kiểm tra để cung cấp bảo hiểm tốt về chức năng mà bạn cung cấp. Điều này đặc biệt đúng ở cấp độ thử nghiệm đơn vị.


1
"Đừng chế giễu phương pháp riêng tư của bạn" vâng, tôi có thể hiểu thử nghiệm, khi bạn chế giễu chúng, bạn có thể đã vượt qua ranh giới tốt đẹp đến điên rồ
Ewan

Vâng nhưng như tôi đã nói, vấn đề của tôi với kiểm thử hộp trắng là thường chế giễu tất cả các phụ thuộc cho các phương thức công khai và riêng tư làm cho các phương pháp kiểm tra thực sự lớn. Bất kỳ ý tưởng làm thế nào để giải quyết điều đó?
Fran Sevillano

8
@FranSevillano Nếu bạn phải sơ khai hoặc chế nhạo nhiều như vậy, tôi sẽ xem xét thiết kế tổng thể của bạn. Một cái gì đó cảm thấy tắt.
Thomas Owens

Một công cụ bao phủ mã giúp với điều này.
Andy

5
@FranSevillano: Không có nhiều lý do chính đáng cho một lớp học làm một việc để có hàng tấn phụ thuộc. Nếu bạn có hàng tấn phụ thuộc, bạn có thể có một lớp Chúa.
Vịt Mooing

4

Tôi nghĩ rằng đây là một ý tưởng rất nghèo.

Vấn đề với việc tạo các bài kiểm tra đơn vị của các thành viên tư nhân, là nó phù hợp với vòng đời sản phẩm.

Lý do bạn CHOSEN để biến các phương thức đó thành riêng tư là vì chúng không tập trung vào những gì lớp bạn đang cố gắng thực hiện - chỉ là người trợ giúp trong cách bạn hiện triển khai chức năng đó. Khi bạn tái cấu trúc, những chi tiết riêng tư đó có khả năng là ứng cử viên thay đổi và sẽ gây ra ma sát sau đó với tái cấu trúc.

Ngoài ra, một điểm khác biệt chính giữa các thành viên công cộng và tư nhân là bạn nên suy nghĩ cẩn thận về API công khai của mình và ghi chép tài liệu tốt và kiểm tra kỹ (xác nhận, v.v.). Nhưng với một API riêng, sẽ thật vô nghĩa khi nghĩ ra một cách cẩn thận (một nỗ lực lãng phí vì việc sử dụng nó quá cục bộ). Đưa các phương thức riêng vào các bài kiểm tra đơn vị để tạo ra sự phụ thuộc bên ngoài vào các phương thức đó. Có nghĩa là API cần phải ổn định và được ghi chép đầy đủ (vì ai đó phải tìm ra lý do tại sao các thử nghiệm đơn vị đó thất bại nếu / khi chúng thực hiện).

Tôi đề nghị bạn:

  • RETHINK liệu các phương thức đó có nên riêng tư không
  • Viết các bài kiểm tra một lần (chỉ để đảm bảo chính xác ngay bây giờ, tạm thời công khai để bạn có thể kiểm tra và sau đó xóa bài kiểm tra)
  • Đã xây dựng thử nghiệm có điều kiện vào việc triển khai của bạn bằng cách sử dụng #ifdef và các xác nhận (các thử nghiệm chỉ được thực hiện trong các bản dựng gỡ lỗi).

Chúng tôi đánh giá cao xu hướng của bạn để kiểm tra chức năng này và thật khó để kiểm tra nó thông qua API công khai hiện tại của bạn. Nhưng cá nhân tôi đánh giá cao tính mô-đun hơn phạm vi kiểm tra.


6
Tôi không đồng ý. IMO, điều này đúng 100% cho các bài kiểm tra tích hợp. Nhưng với bài kiểm tra đơn vị thì mọi thứ lại khác; Mục tiêu của kiểm thử đơn vị là xác định chính xác lỗi ở đâu, đủ hẹp để bạn có thể khắc phục nhanh chóng. Tôi thấy mình thường xuyên trong tình huống này: tôi có rất ít phương thức công khai vì đó thực sự là giá trị cốt lõi của các lớp học của tôi (như bạn đã nói nên làm). Tuy nhiên, tôi cũng tránh viết 400 phương thức dòng, không công khai hay riêng tư. Vì vậy, một vài phương thức công khai của tôi chỉ có thể đạt được mục tiêu của họ với sự trợ giúp của hàng chục phương thức riêng tư. Đó là quá nhiều mã để "nhanh chóng sửa nó". Tôi phải bắt đầu trình gỡ lỗi, v.v.
marstato

6
@marstato: đề xuất: bắt đầu viết bài kiểm tra trước và thay đổi suy nghĩ của bạn về những điều không mong muốn: họ không tìm thấy lỗi, nhưng xác minh rằng mã hoạt động như nhà phát triển dự định.
Timothy Truckle

@marstato Cảm ơn bạn! Đúng. Các bài kiểm tra luôn vượt qua lần đầu tiên, khi bạn kiểm tra nội dung (hoặc bạn sẽ không kiểm tra!). Chúng rất hữu ích, khi bạn phát triển mã, cho bạn một cái đầu khi bạn phá vỡ một cái gì đó và nếu bạn có các bài kiểm tra hồi quy TỐT, thì chúng sẽ cung cấp cho bạn HOÀN TOÀN / HƯỚNG DẪN về nơi tìm kiếm các vấn đề (không phải trong công cụ ổn định và kiểm tra hồi quy tốt).
Lewis Pringle

@marstato "Mục tiêu của kiểm tra đơn vị là xác định chính xác lỗi ở đâu" - Đó chính xác là sự hiểu lầm dẫn đến câu hỏi của OP. Mục tiêu của kiểm thử đơn vị là xác minh hành vi dự định (và tốt nhất là được ghi lại) của API.
dùng560822

4
@marstato Tên "kiểm thử tích hợp" xuất phát từ kiểm tra rằng nhiều thành phần hoạt động cùng nhau (nghĩa là chúng tích hợp đúng cách). Kiểm thử đơn vị đang kiểm tra một thành phần duy nhất thực hiện những gì nó được thực hiện một cách cô lập, điều đó về cơ bản có nghĩa là API công khai của nó hoạt động như tài liệu / yêu cầu. Cả hai điều khoản này đều không nói gì về việc bạn có bao gồm các bài kiểm tra logic thực hiện nội bộ như là một phần của việc đảm bảo tích hợp hoạt động hay đơn vị duy nhất hoạt động.
Ben

3

UnitTests kiểm tra hành vi có thể quan sát được của công chúng , không phải mã, trong đó "công khai" có nghĩa là: trả về giá trị và liên lạc với các phụ thuộc.

"Đơn vị" là bất kỳ mã nào, giải quyết cùng một vấn đề (hoặc chính xác hơn: có cùng lý do để thay đổi). Đó có thể là một phương thức đơn lẻ hoặc một nhóm các lớp.

Lý do chính khiến bạn không muốn kiểm tra private methodslà: chúng là chi tiết triển khai và bạn có thể muốn thay đổi chúng trong quá trình tái cấu trúc (cải thiện mã của bạn bằng cách áp dụng các nguyên tắc OO mà không thay đổi chức năng). Điều này chính xác là khi bạn không muốn sự thay đổi của mình thay đổi để họ có thể đảm bảo hành vi của CuT của bạn không thay đổi trong quá trình tái cấu trúc.

Nhưng, tôi không muốn có một lớp học chỉ để tôi có thể kiểm tra các giao diện công cộng của chúng và tôi thấy rằng đối với nhiều lớp nếu tôi chỉ kiểm tra các phương thức công khai thì cuối cùng tôi phải chế giễu rất nhiều phụ thuộc và các bài kiểm tra đơn vị là to lớn và khó theo dõi

Tôi thường trải nghiệm điều ngược lại: Các lớp càng nhỏ (họ càng ít trách nhiệm) thì họ càng ít phụ thuộc và càng dễ dàng hơn trong việc viết và đọc.

Lý tưởng nhất là bạn áp dụng cùng một mức độ trừu tượng cho các lớp học của bạn. Điều này có nghĩa là các lớp của bạn cung cấp một số logic nghiệp vụ (tốt nhất là "các hàm thuần túy" chỉ hoạt động trên các tham số của chúng mà không duy trì trạng thái riêng) (x) hoặc gọi các phương thức trên các đối tượng khác, không phải cả hai cùng một lúc.

Cách này không coi trọng hành vi kinh doanh là một miếng bánh và các đối tượng "ủy nhiệm" thường quá đơn giản để thất bại (không phân nhánh, không thay đổi trạng thái) để không cần thiết phải kiểm tra và có thể bỏ qua thử nghiệm tích hợp hoặc kiểm tra mô-đun


1

Kiểm thử đơn vị có một số giá trị khi bạn là lập trình viên duy nhất làm việc với mã, đặc biệt nếu ứng dụng rất lớn hoặc rất phức tạp. Trường hợp kiểm thử đơn vị trở nên thiết yếu là khi bạn có số lượng lập trình viên lớn hơn làm việc trên cùng một cơ sở mã. Khái niệm thử nghiệm đơn vị đã được giới thiệu để giải quyết một số khó khăn khi làm việc trong các nhóm lớn hơn này.

Lý do mà các bài kiểm tra đơn vị giúp các đội lớn hơn là tất cả về hợp đồng. Nếu mã của tôi đang thực hiện các cuộc gọi đến mã được viết bởi người khác, tôi sẽ đưa ra các giả định về những gì mã của người khác sẽ làm trong các tình huống khác nhau. Miễn là các giả định đó vẫn đúng, mã của tôi sẽ vẫn hoạt động, nhưng làm cách nào để biết giả định nào là hợp lệ và làm sao để biết khi nào các giả định đó thay đổi?

Đây là nơi các bài kiểm tra đơn vị đến. Tác giả của một lớp tạo ra các bài kiểm tra đơn vị để ghi lại hành vi dự kiến ​​của lớp của họ. Kiểm thử đơn vị xác định tất cả các cách sử dụng lớp hợp lệ và chạy thử nghiệm đơn vị xác nhận các trường hợp sử dụng này hoạt động như mong đợi. Một lập trình viên khác muốn sử dụng lớp của bạn có thể đọc các bài kiểm tra đơn vị của bạn để hiểu hành vi họ có thể mong đợi cho lớp của bạn và sử dụng điều này làm cơ sở cho các giả định của họ về cách lớp của bạn hoạt động.

Theo cách này, các chữ ký phương thức công khai của lớp và đơn vị kiểm tra cùng nhau tạo thành một hợp đồng giữa tác giả lớp và các lập trình viên khác sử dụng lớp này trong mã của họ.

Trong kịch bản này, điều gì xảy ra nếu bạn bao gồm thử nghiệm các phương thức riêng tư? Rõ ràng nó không có ý nghĩa.

Nếu bạn là lập trình viên duy nhất làm việc với mã của bạn và bạn muốn sử dụng thử nghiệm đơn vị như một cách để gỡ lỗi mã của mình thì tôi không thấy có hại gì trong đó, đó chỉ là một công cụ và bạn có thể sử dụng nó theo bất kỳ cách nào phù hợp bạn, nhưng đó không phải là lý do tại sao thử nghiệm đơn vị được giới thiệu và không cung cấp những lợi ích chính của thử nghiệm đơn vị.


Tôi đấu tranh với điều này ở chỗ tôi chế nhạo những người phụ thuộc để nếu bất kỳ sự phụ thuộc nào thay đổi hành vi của nó, thử nghiệm của tôi sẽ không thất bại. Là thất bại này được cho là xảy ra trong một bài kiểm tra tích hợp không phải là bài kiểm tra đơn vị?
Todd

Mock được cho là hành xử giống hệt với việc thực hiện thực sự, nhưng không có sự phụ thuộc. Nếu việc triển khai thực sự thay đổi để bây giờ chúng khác đi thì điều này sẽ hiển thị như một lỗi thử nghiệm tích hợp. Cá nhân tôi coi sự phát triển của giả và thực hiện thực sự là một nhiệm vụ. Tôi không xây dựng giả như là một phần của bài kiểm tra đơn vị. Theo cách này khi tôi thay đổi hành vi lớp học và thay đổi giả định cho phù hợp, chạy thử nghiệm đơn vị sẽ xác định tất cả các lớp khác đã bị phá vỡ bởi thay đổi này.
bikeman868

1

Trước khi trả lời một câu hỏi như vậy, bạn cần phải quyết định những gì bạn thực sự muốn đạt được.

Bạn viết mã. Bạn hy vọng nó hoàn thành hợp đồng của mình (nói cách khác, nó thực hiện những gì nó phải làm. Viết ra những gì nó phải làm là một bước tiến khổng lồ đối với một số người).

Để được thuyết phục một cách hợp lý rằng mã thực hiện những gì nó phải làm, bạn sẽ nhìn chằm chằm vào nó đủ lâu hoặc bạn viết mã kiểm tra để kiểm tra đủ các trường hợp để thuyết phục bạn "nếu mã vượt qua tất cả các thử nghiệm này thì đó là chính xác".

Thường thì bạn chỉ quan tâm đến giao diện được xác định công khai của một số mã. Nếu tôi sử dụng thư viện của bạn, tôi không quan tâm làm thế nào bạn đã làm cho nó hoạt động chính xác, duy nhất mà nó không hoạt động chính xác. Tôi xác minh rằng thư viện của bạn là chính xác bằng cách thực hiện các bài kiểm tra đơn vị.

Nhưng bạn đang tạo thư viện. Làm cho nó hoạt động chính xác có thể khó đạt được. Giả sử tôi chỉ quan tâm đến thư viện thực hiện thao tác X một cách chính xác, vì vậy tôi có một bài kiểm tra đơn vị cho X. Bạn, nhà phát triển chịu trách nhiệm tạo thư viện, thực hiện X bằng cách kết hợp các bước A, B và C, mỗi bước hoàn toàn không cần thiết. Để thư viện của bạn hoạt động, bạn thêm các bài kiểm tra để xác minh rằng A, B và C từng hoạt động chính xác. Bạn muốn những bài kiểm tra này. Nói rằng "bạn không nên có các bài kiểm tra đơn vị cho các phương thức riêng tư" là khá vô nghĩa. Bạn muốn thử nghiệm cho các phương pháp riêng tư này. Có thể ai đó nói với bạn rằng đơn vị thử nghiệm phương pháp riêng tư là sai. Nhưng điều đó chỉ có nghĩa là bạn có thể không gọi chúng là "bài kiểm tra đơn vị" mà là "bài kiểm tra riêng" hoặc bất cứ điều gì bạn muốn gọi chúng.

Ngôn ngữ Swift giải quyết vấn đề mà bạn không muốn đưa A, B, C thành các phương thức công khai chỉ vì bạn muốn kiểm tra nó bằng cách cung cấp cho các hàm một thuộc tính "có thể kiểm tra". Trình biên dịch cho phép các phương thức kiểm tra riêng được gọi từ các bài kiểm tra đơn vị, nhưng không phải từ mã không kiểm tra.


0

Vâng, bạn thật điên rồ .... THÍCH MỘT FOX!

Có một số cách để kiểm tra các phương thức riêng tư, một số trong số đó phụ thuộc vào ngôn ngữ.

  • suy tư! quy tắc được thực hiện để được phá vỡ!
  • làm cho chúng được bảo vệ, kế thừa và ghi đè
  • bạn bè / InternalsVisibleTo lớp

Nhìn chung, nếu bạn muốn thử nghiệm các phương thức riêng tư, có lẽ bạn muốn chuyển chúng sang các phương thức công khai dựa trên sự phụ thuộc và thử nghiệm / tiêm đó.


Tôi không biết, trong mắt tôi, bạn giải thích rằng đó không phải là một ý tưởng hay nhưng vẫn tiếp tục trả lời câu hỏi
Liath

Tôi nghĩ rằng tôi có tất cả các căn cứ được bảo hiểm :(
Ewan

3
Tôi ủng hộ, vì ý tưởng đưa ra các phương thức trợ giúp riêng tư của bạn cho API công khai chỉ để kiểm tra chúng là điên rồ, và tôi luôn nghĩ rằng.
Robert Harvey

0

Hãy thực dụng. Kiểm tra các trường hợp đặc biệt trong các phương thức riêng bằng cách thiết lập trạng thái của thể hiện và các tham số cho một phương thức công khai sao cho các trường hợp đó xảy ra ở đó, thường quá phức tạp.

Tôi thêm một bộ truy cập bổ sung internal(cùng với cờ InternalsVisibleTolắp ráp thử nghiệm), được đặt tên rõ ràng DoSomethingForTesting(parameters), để kiểm tra các phương thức "riêng tư" đó.

Tất nhiên, việc thực hiện có thể thay đổi một cách nào đó và những thử nghiệm bao gồm cả những người truy cập thử nghiệm trở nên lỗi thời. Điều đó vẫn tốt hơn so với các trường hợp chưa được kiểm tra hoặc các xét nghiệm không thể đọc được.

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.