2011-08-16 6 views
7

Có nhiều ý kiến ​​khác nhau về ý nghĩa của việc thử nghiệm các phương pháp riêng tư, ví dụ: herehere. Cá nhân tôi nghĩ rằng nó có ý nghĩa, câu hỏi là làm thế nào để làm điều đó đúng. Trong C++, bạn có thể sử dụng #define hack hoặc tạo lớp kiểm tra friend, trong C# có InternalsVisibleToAttribute, nhưng trong Java, chúng tôi phải sử dụng reflection hoặc để làm cho chúng "hiển thị để kiểm tra" và annotate them as such. Những bất lợi của cả hai nên khá rõ ràng.Công cụ Java để thử nghiệm các phương pháp riêng tư?

Tôi nghĩ nên có điều gì đó tốt hơn. Bắt đầu với

public class Something { 
    private int internalSecret() { 
     return 43; 
    } 
} 

nó sẽ được tốt đẹp để có thể gọi các phương thức tư nhân trong mã kiểm tra như

@MakeVisibleForTesting Something something = new Something(); 
Assert.assertEquals(43, something.internalSecret()); 

Ở đây, chú thích âm thầm sẽ chuyển đổi tất cả các cuộc gọi đến các phương pháp riêng của something sử dụng phản ánh. Tôi tự hỏi nếu Lombok có thể làm điều đó (và sẽ yêu cầu các tác giả). Có thể thực hiện nhiều phép thuật chứng tỏ quá phức tạp, và trong mọi trường hợp, nó sẽ mất một thời gian, vì vậy tôi đang tìm kiếm một số thay thế. Có lẽ chú thích lớp dưới kiểm tra với một cái gì đó giống như @Decapsulate và sử dụng một bộ xử lý chú thích để tạo ra một lớp Decapsulated_Something trông như

public class Decapsulated_Something { 
    public Decapsulated_Something(Something delegate) { 
     this.delegate = delegate 
    } 
    public boolean internalSecret() { 
     // call "delegate.internalSecret()" using reflection 
    } 
    ... 
} 

mà sẽ cho phép sử dụng

Decapsulated_Something something = new Decapsulated_Something(new Something()); 
Assert.assertEquals(43, something.internalSecret()); 

Tôi không có nhiều kinh nghiệm với chú thích xử lý, vì vậy tôi hỏi đầu tiên ở đây:

  • Việc này phức tạp như thế nào?
  • Tôi đã quên gì?
  • Bạn nghĩ gì về nó nói chung?
+0

Bạn đang yêu cầu một công cụ linh hoạt, hoặc làm thế nào để viết một mình? – Raedwald

+0

@Raedwald Tôi đang hỏi cách giải quyết nó. Vắt bản thân mình là một lựa chọn, nhưng việc phát minh lại bánh xe không được mong muốn một cách rõ ràng. – maaartinus

Trả lời

1

nó sẽ được tốt đẹp để có thể gọi các phương thức tư nhân trong mã kiểm tra như

@MakeVisibleForTesting Something something = new Something(); 
Assert.assertEquals(43, something.internalSecret()); 

Có những điều như một chú thích phương pháp, kiểm tra dp4j 's @TestPrivates:

@Test 
@TestPrivates 
//since the method is annotated with JUnit's @Test this annotation is redundant. 
// You just need to have dp4j on the classpath. 
    public void somethingTest(){ 
     Something something = new Something(); 
     int sthSecret = something.internalSecret(); 
     Assert.assertEquals(43, sthSecret); //cannot use something.internalSecret() directly because of bug [dp4j-13][2] 
    } 
7

Có vẻ như rất nhiều rắc rối khi thực hiện việc triển khai này. Nó có thể không có giá trị nó. Thay vào đó chỉ làm cho gói phương thức mặc định.

Tuy nhiên, nếu bạn được xác định là gọi phương thức riêng tư, bạn có thể sử dụng setAccessible trong lớp Decapsulated_something để cho phép gọi qua phản ánh. Vì vậy, nó khá đơn giản.

+0

+1 cho gói riêng tư. – Thilo

1

Tôi sẽ trả lời câu hỏi "Nói chung" :-) Chỉ cần một vài dòng mã để làm cho một phương thức có thể truy cập thông qua phản ánh và có một số thư viện, utils, APIs, vv cung cấp các phương thức để làm vì thế. Cũng có thể có nhiều kỹ thuật khác nhau mà bạn có thể sử dụng trong mã của riêng bạn. Ví dụ như thao tác bytecode, sự phản chiếu, phần mở rộng của lớp, v.v. Nhưng tôi muốn nghiêng về mọi thứ đơn giản. Trong khi nó có thể hữu ích để kiểm tra các phương thức riêng, nó cũng có khả năng là bạn sẽ chỉ muốn thử nghiệm một vài. Vì vậy, một cái gì đó phức tạp kỹ thuật có lẽ là quá mức cần thiết. Tôi chỉ sử dụng một API được thiết lập, hoặc viết một phương thức nhanh để truy cập các phương thức riêng mà tôi quan tâm và để nó được thực hiện tại đó.

1

Có số phương pháp để có

  • Đừng thử nghiệm phương pháp tư nhân khi họ đang ẩn chi tiết thực hiện mà không bao giờ nên tạo sự khác biệt cho người gọi.
  • Đặt gói phương thức cục bộ để người gọi không thể truy cập chúng, nhưng bạn có thể truy cập chúng trong cùng một gói, nghĩa là kiểm tra đơn vị.
  • Làm cho thiết bị thử nghiệm một lớp bên trong hoặc cung cấp một lớp bên trong gói nội bộ. Không chắc chắn đây là một sự cải tiến!
  • Sử dụng phản ánh để truy cập các phương thức của lớp học. Điều này cũng giống như đánh dấu một phương pháp rpivate khi nó không và là một IMHO nhầm lẫn. Bạn chỉ nên đánh dấu một phương thức riêng tư khi nó thực sự là riêng tư.
1

Tôi đã làm việc trên một dự án một vài năm trước rằng các lớp học được tạo ra để làm cho nó dễ dàng hơn để kiểm tra các phương pháp riêng tư đơn vị. http://java.net/projects/privateer/

Nó tạo ra các lớp bổ sung giúp dễ dàng hơn gọi điện cho sự phản chiếu, ví dụ: nếu bạn có MyClass.myPrivateMethod() nó sẽ tạo ra một lớp _MyClass cho phép gọi trực tiếp myPrivateMethod.

Nó chưa bao giờ thực sự hoàn thành và hữu ích cho một vài trường hợp, nhưng nói chung tôi sẽ không khuyên bạn thử nghiệm các phương thức riêng trừ khi thực sự cần thiết. Thường thiết kế lại chúng thành các lớp tiện ích (với quyền truy cập gói nếu bạn lo lắng về việc người dùng sử dụng chúng) là một lựa chọn tốt hơn.