Câu hỏi Làm thế nào để kiểm tra một hàm riêng hoặc một lớp có các phương thức riêng, các trường hoặc các lớp bên trong?


Làm thế nào để kiểm thử đơn vị (sử dụng xUnit) một lớp có các phương thức riêng tư nội bộ, các trường hoặc các lớp lồng nhau? Hoặc một hàm được đặt ở chế độ riêng tư bằng cách liên kết nội bộ (static trong C / C ++) hoặc đang ở chế độ riêng tư (vô danh) không gian tên?

Có vẻ xấu khi thay đổi công cụ sửa đổi truy cập cho một phương thức hoặc chức năng chỉ để có thể chạy thử nghiệm.


2268


gốc


Cách tốt nhất để thử nghiệm một phương pháp riêng tư là không kiểm tra trực tiếp - Surya
Kiểm tra bài viết Thử nghiệm các phương thức riêng với JUnit và SuiteRunner. - Mouna Cheikhna
Tôi không đồng ý. Phương thức (công khai) dài hoặc khó hiểu phải được tái cấu trúc. Nó sẽ là điên rồ không để kiểm tra các phương pháp nhỏ (tư nhân) mà bạn nhận được thay vì chỉ có một công cộng. - Michael Piefel
Không thử nghiệm bất kỳ phương pháp nào chỉ vì khả năng hiển thị của nó là ngu xuẩn. Ngay cả kiểm thử đơn vị cũng phải là đoạn mã nhỏ nhất, và nếu bạn chỉ thử nghiệm các phương thức công khai, bạn sẽ không bao giờ dám chắc chắn nơi xảy ra lỗi - phương thức đó, hoặc một số khác. - Dainius
Bạn cần phải kiểm tra lớp chức năng, không phải của nó thực hiện. Muốn kiểm tra các phương pháp riêng tư? Kiểm tra các phương thức công khai gọi chúng. Nếu chức năng mà lớp học cung cấp được kiểm tra kỹ lưỡng, các phần tử bên trong của nó đã chứng minh là chính xác và đáng tin cậy; bạn không cần phải kiểm tra các điều kiện bên trong. Các bài kiểm tra nên duy trì tách khỏi các lớp được kiểm tra. - Calimar41


Các câu trả lời:


Nếu bạn có một phần của di sản Java ứng dụng và bạn không được phép thay đổi chế độ hiển thị của các phương pháp của mình, cách tốt nhất để thử nghiệm các phương pháp riêng tư là sử dụng sự phản chiếu.

Nội bộ chúng tôi đang sử dụng người trợ giúp để có được / thiết lập private và private static biến cũng như gọi private và private static phương pháp. Các mẫu sau sẽ cho phép bạn thực hiện khá nhiều thứ liên quan đến các phương thức và trường riêng tư. Tất nhiên bạn không thể thay đổi private static final biến thông qua sự phản chiếu.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Và đối với các trường:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Ghi chú:
  1. targetClass.getDeclaredMethod(methodName, argClasses) cho phép bạn nhìn vào private phương pháp. Điều tương tự cũng áp dụng cho    getDeclaredField.
  2. The setAccessible(true) là cần thiết để chơi xung quanh với các cá nhân.


1417



Hữu ích nếu bạn không biết các API có lẽ, nhưng nếu bạn đang có để thử nghiệm các phương pháp tư nhân theo cách này có cái gì đó với thiết kế của bạn. Là một poster khác nói rằng kiểm tra đơn vị nên kiểm tra hợp đồng của lớp: nếu hợp đồng quá rộng và khởi tạo quá nhiều hệ thống thì thiết kế nên được giải quyết. - andygavin
Rất hữu dụng. Sử dụng điều này, điều quan trọng là phải ghi nhớ rằng nó sẽ thất bại nặng nề nếu các bài kiểm tra được chạy bài obfuscation. - Rick Minerich
Mã ví dụ không hoạt động đối với tôi, nhưng điều này đã làm cho rõ ràng hơn: java2s.com/Tutorial/Java/0125__Reflection/… - Rob
Tốt hơn nhiều so với việc sử dụng sự phản chiếu trực tiếp sẽ là sử dụng một số thư viện cho nó như Powermock. - Michael Piefel
Đây là lý do tại sao Test Driven Design là hữu ích. Nó giúp bạn tìm ra những gì cần phải được tiếp xúc để xác nhận hành vi. - Thorbjørn Ravn Andersen


Cách tốt nhất để kiểm tra phương thức riêng là thông qua phương thức công khai khác. Nếu điều này không thể thực hiện được thì một trong các điều kiện sau là đúng:

  1. Phương thức riêng là mã chết
  2. Có một mùi thiết kế gần lớp mà bạn đang thử nghiệm
  3. Phương pháp mà bạn đang cố kiểm tra không nên là riêng tư

507



Không đồng ý. Nó hoàn toàn hợp lệ để có một thuật toán trong một phương thức riêng mà cần nhiều thử nghiệm đơn vị hơn là thực tế thông qua các giao diện công cộng của lớp. - Mr. Shiny and New 安宇
Hey Ông Shiny Có, nhưng sau đó bạn sẽ có các xét nghiệm giòn. Ngoài ra, xem số 2 trong thư trả lời của tôi. - Trumpi
Một thử nghiệm giòn là một thử nghiệm không thành công quá dễ dàng khi có sự thay đổi trong mã. Nói chung điều này xảy ra khi kết quả thử nghiệm dựa trên những gì phương pháp làm thay vì trên đầu ra dự kiến ​​và tác dụng phụ cho một tập hợp các đầu vào. Lý tưởng nhất, một sự thay đổi mã mà không thay đổi kết quả sẽ không phá vỡ thử nghiệm. - aro_biz
@Ông. Sáng bóng và mới: Nếu phương pháp riêng của bạn đủ phức tạp để đảm bảo thử nghiệm đơn vị độc lập, thì nó đủ phức tạp để có lớp riêng của nó. Lớp học có thể là nội bộ của khóa học (tức là không thể truy cập từ các gói khác). - sleske
@sleske, tôi không đồng ý. Bạn có thể có một phương pháp riêng tư nhỏ theo thiết kế mà bạn cần nó là riêng tư. và tôi muốn kiểm tra từng đoạn mã nhỏ hơn là kiểm tra phương thức riêng thông qua phương thức công khai. Cách kiểm tra này sẽ tiến tới thử nghiệm thành phần. - despot


Khi tôi có các phương thức riêng trong một lớp đủ phức tạp đến nỗi tôi cảm thấy cần phải kiểm tra trực tiếp các phương thức riêng, đó là một mùi mã: lớp của tôi quá phức tạp.

Cách tiếp cận thông thường của tôi để giải quyết các vấn đề như vậy là trêu chọc một lớp mới chứa các bit thú vị. Thông thường, phương thức này và các trường tương tác với nó và có thể một hoặc hai phương thức khác có thể được trích xuất vào một lớp mới.

Lớp mới hiển thị các phương thức này là 'công khai', vì vậy chúng có thể truy cập để kiểm tra đơn vị. Các lớp học mới và cũ bây giờ đơn giản hơn cả lớp gốc, điều này thật tuyệt vời đối với tôi (tôi cần giữ cho mọi thứ đơn giản, hoặc tôi bị lạc!).

Lưu ý rằng tôi không gợi ý rằng mọi người tạo ra các lớp học mà không cần sử dụng bộ não của họ! Vấn đề ở đây là sử dụng các lực lượng kiểm tra đơn vị để giúp bạn tìm được các lớp học mới tốt.


272



Câu hỏi là làm thế nào để kiểm tra các phương pháp riêng. Bạn nói rằng bạn sẽ làm lớp mới cho điều đó (và thêm nhiều phức tạp hơn) và sau khi đề nghị không tạo lớp mới. Vậy làm cách nào để thử nghiệm các phương thức riêng tư? - Dainius
Tôi nghĩ rằng nếu bạn có phương pháp thì không cần phải tạo một lớp khác để có thể kiểm tra phương thức đó. Tôi không nghĩ rằng thiết kế lớp học là câu hỏi ở đây .. Vì vậy, tôi giả định rằng tác giả đã làm mọi thứ để có thiết kế thích hợp trước đây, vì vậy giới thiệu một lớp học cho một phương pháp bạn chỉ tăng độ phức tạp. Tất nhiên khi bạn có đủ chương trình phức tạp, sẽ không có lỗi rõ ràng nào .. - Dainius
@ David: Tôi không đề nghị tạo một lớp học mới chỉ duy nhất để bạn có thể kiểm tra phương pháp đó. Tôi đề nghị rằng các bài kiểm tra viết có thể giúp bạn cải thiện thiết kế của mình: các thiết kế tốt rất dễ kiểm tra. - Jay Bazuzi
Nhưng bạn đồng ý rằng tốt OOD sẽ phơi bày (làm cho công cộng) chỉ có phương pháp đó là cần thiết cho rằng lớp / đối tượng để làm việc một cách chính xác? tất cả những thứ khác nên là private / protectec. Vì vậy, trong một số phương pháp riêng tư sẽ có một số logic, và IMO thử nghiệm các phương pháp này sẽ chỉ cải thiện chất lượng của phần mềm. Tất nhiên tôi đồng ý rằng nếu một số đoạn mã là phức tạp, nó phải được chia thành các phương thức / lớp riêng biệt. - Dainius
@ Danius: Thêm một lớp mới, trong hầu hết các trường hợp làm giảm sự phức tạp. Chỉ cần đo nó. Testability trong một số trường hợp chiến đấu chống lại OOD. Cách tiếp cận hiện đại là khả năng thử nghiệm ưu tiên. - AlexWien


tôi đã sử dụng sự phản chiếu để làm điều này cho Java trong quá khứ, và theo tôi, đó là một sai lầm lớn.

Nói đúng ra, bạn nên không phải viết các bài kiểm tra đơn vị trực tiếp kiểm tra các phương thức riêng. Bạn là gì Nên kiểm tra là hợp đồng công khai mà lớp đó có với các đối tượng khác; bạn không bao giờ nên trực tiếp kiểm tra nội bộ của đối tượng. Nếu một nhà phát triển khác muốn thực hiện một thay đổi nhỏ bên trong lớp, điều này không ảnh hưởng đến hợp đồng công khai của lớp, thì anh ta / cô ấy phải sửa đổi phép thử dựa trên phản chiếu của bạn để đảm bảo nó hoạt động. Nếu bạn làm điều này nhiều lần trong suốt một dự án, các bài kiểm tra đơn vị sau đó dừng lại là một phép đo hữu ích về sức khỏe mã, và bắt đầu trở thành một trở ngại cho sự phát triển và gây phiền toái cho nhóm phát triển.

Những gì tôi khuyên bạn nên làm thay vì sử dụng một công cụ bảo hiểm mã như Cobertura, để đảm bảo rằng các bài kiểm tra đơn vị bạn viết cung cấp bảo hiểm phong nha của mã trong phương pháp riêng. Bằng cách đó, bạn gián tiếp kiểm tra những gì các phương pháp riêng tư đang làm, và duy trì một mức độ nhanh nhẹn của sự nhanh nhẹn.


229



+1 này. Theo tôi, đó là câu trả lời hay nhất cho câu hỏi. Bằng cách thử nghiệm các phương thức riêng, bạn đang thử nghiệm việc thực hiện. Điều này đánh bại mục đích của thử nghiệm đơn vị, đó là để kiểm tra đầu vào / đầu ra của hợp đồng của một lớp. Thử nghiệm nên chỉ có biết đủ về việc triển khai để giả lập các phương thức mà nó gọi dựa trên các phụ thuộc của nó. Chỉ có bấy nhiêu thôi. Nếu bạn không thể thay đổi việc triển khai của mình mà không phải thay đổi thử nghiệm - rất có thể là chiến lược thử nghiệm của bạn kém. - Colin M
@ Colin M Đó không thực sự là những gì anh ấy hỏi mặc dù;) Hãy để anh ta quyết định nó, bạn không biết dự án. - Aaron Marcus
Không thực sự đúng. Nó có thể mất rất nhiều nỗ lực để kiểm tra một phần nhỏ của phương pháp riêng thông qua phương pháp công cộng sử dụng nó. Phương pháp công khai có thể yêu cầu thiết lập quan trọng trước khi bạn đến được đường gọi phương thức riêng tư của bạn - ACV


Từ bài viết này: Thử nghiệm các phương thức riêng với JUnit và SuiteRunner (Bill Venners), về cơ bản bạn có 4 lựa chọn:

  • Đừng thử nghiệm các phương thức riêng.
  • Cung cấp cho các gói phương thức truy cập.
  • Sử dụng một lớp thử nghiệm lồng nhau.
  • Sử dụng sự phản chiếu.

187



@ user86614 Đưa mã kiểm tra vào mã sản xuất không phải là một ý tưởng hay. - Jimmy T.
@JimmyT., Phụ thuộc vào "mã sản xuất" dành cho ai. Tôi sẽ gọi mã được tạo ra cho các ứng dụng được đóng trong VPN mà người dùng đích là hệ thống quản trị mã sản xuất. - Pacerier
@Pacerier Bạn có ý gì? - Jimmy T.
Tùy chọn thứ 5, như đã đề cập ở trên là thử nghiệm phương thức công khai gọi phương thức riêng tư? Chính xác? - user2441441
@LorenzoLerate Tôi đã vật lộn với điều này bởi vì tôi đang làm phát triển nhúng và tôi muốn phần mềm của tôi càng nhỏ càng tốt. Ràng buộc kích thước và hiệu suất là lý do duy nhất tôi có thể nghĩ đến.


Nói chung một bài kiểm tra đơn vị được thiết kế để thực hiện giao diện công cộng của một lớp hoặc đơn vị. Do đó, các phương thức riêng tư là các chi tiết triển khai mà bạn sẽ không mong đợi để kiểm tra một cách rõ ràng.


96



Đó là câu trả lời hay nhất IMO, hoặc như thường nói, hành vi kiểm tra, không phải phương pháp. Kiểm thử đơn vị không thay thế cho các chỉ số mã nguồn, các công cụ phân tích mã tĩnh và các đánh giá mã. Nếu các phương thức riêng tư phức tạp đến mức chúng cần phân tách các phép thử thì có lẽ nó cần phải được tái cấu trúc, không phải nhiều thử nghiệm được ném vào nó. - Dan Haynes
vì vậy đừng viết các phương thức riêng, chỉ cần tạo 10 lớp nhỏ khác? - razor


Chỉ cần hai ví dụ về nơi tôi sẽ muốn thử nghiệm một phương pháp riêng:

  1. Các thói quen giải mã - Tôi sẽ không muốn hiển thị chúng cho mọi người chỉ xem vì mục đích thử nghiệm, bất kỳ ai cũng có thể sử dụng chúng để giải mã. Nhưng chúng nội tại mã, phức tạp, và cần phải luôn luôn làm việc (ngoại lệ rõ ràng là sự phản chiếu có thể được sử dụng để xem các phương thức riêng tư trong hầu hết các trường hợp, khi SecurityManager không được cấu hình để ngăn chặn điều này).
  2. Tạo SDK cho cộng đồng tiêu thụ. Ở đây, công chúng có một ý nghĩa hoàn toàn khác, vì điều này là mã mà cả thế giới có thể thấy (không chỉ nội bộ cho đơn xin của tôi). tôi đặt mã vào các phương thức riêng nếu tôi không muốn người dùng SDK thấy nó - tôi không thấy điều này như mùi mã, chỉ đơn thuần là cách lập trình SDK hoạt động. Nhưng của tất nhiên tôi vẫn cần kiểm tra phương pháp riêng tư và chúng là nơi chức năng của SDK của tôi thực sự cuộc sống.

Tôi hiểu ý tưởng chỉ thử nghiệm "hợp đồng". Nhưng tôi không thấy ai có thể bênh vực thực sự không kiểm tra mã - số dặm của bạn có thể thay đổi.

Vì vậy, sự cân bằng của tôi liên quan đến việc làm phức tạp JUnits với sự phản ánh, thay vì ảnh hưởng đến bảo mật và SDK của tôi.


56



Mặc dù bạn không bao giờ nên đặt phương thức công khai chỉ để kiểm tra nó, private không phải là lựa chọn duy nhất. Không có công cụ sửa đổi truy cập nào là package private và có nghĩa là bạn có thể kiểm tra đơn vị nó miễn là kiểm tra đơn vị của bạn sống trong cùng một gói. - ngreen
@ màn hình đó là tất cả sự thật, nhưng không phải là những gì câu hỏi là về. OP hỏi về việc thử nghiệm các phương thức riêng. Mặc định không giống như riêng tư; như đã nói, bạn có thể dễ dàng nhìn thấy một phương thức truy cập mặc định từ một lớp chỉ bằng cách khai báo lớp đó trong cùng một gói. Với quyền truy cập riêng tư, bạn cần phản ánh, đó là một trò chơi bóng khác. - Richard Le Mesurier
Tôi đã bình luận về câu trả lời của bạn, điểm 1 nói riêng, không phải OP. Không cần phải thực hiện một phương thức riêng tư chỉ vì bạn không muốn nó được công khai. - ngreen
@ngreen true thx - Tôi đã lười biếng với từ "công khai". Tôi đã cập nhật câu trả lời để bao gồm công khai, được bảo vệ, mặc định (và đề cập đến sự phản ánh). Điểm tôi cố gắng tạo ra là có lý do chính đáng để một số mã bí mật, tuy nhiên điều đó không ngăn cản chúng tôi thử nghiệm nó. - Richard Le Mesurier
Cảm ơn bạn đã đưa ra các ví dụ thực tế cho mọi người. Hầu hết các câu trả lời đều tốt, nhưng theo quan điểm lý thuyết. Trong thế giới thực, chúng ta cần phải che giấu việc thực hiện từ hợp đồng, và chúng ta vẫn cần phải thử nghiệm nó. Đọc tất cả những điều này, tôi nghĩ rằng đây có thể là một cấp độ thử nghiệm hoàn toàn mới, với một tên khác - Z. Khullah