2012-03-14 31 views
27

Tôi đang thử nghiệm một lớp trợ giúp chỉ với các phương thức tĩnh với JUnit4 và Cobertura. Phương pháp thử nghiệm là nhiệm vụ dễ dàng và đã hoàn thành.JUnit: lớp trình trợ giúp thử nghiệm chỉ với các phương thức tĩnh

Tuy nhiên, cobertura cho thấy lớp học không được kiểm tra hoàn toàn bởi vì nó không được khởi tạo ở bất cứ đâu.

Tôi không muốn tạo một thể hiện của lớp này (nó là một lớp trợ giúp), vì vậy giải pháp đầu tiên là ẩn hàm tạo (thường là cách tiếp cận tốt cho lớp trợ giúp).

Sau đó, cobertura phàn nàn rằng hàm tạo riêng tư trống không được kiểm tra.

Có giải pháp nào để đạt được mức độ bao phủ mã 100% cho tình huống như vậy không?

Phạm vi mã được yêu cầu từ cấp quản lý cấp cao nhất (trong trường hợp này), do đó, để tôi có được 100% cho lớp học cụ thể này là khá hữu ích.

Trả lời

27

Có một số giải pháp:

  1. Bạn có thể thêm một constructor công cộng và gọi nó là từ một thử nghiệm. Trong khi nó không có ý nghĩa, nó cũng không đau (nhiều).

  2. Tạo một trường hợp tĩnh giả (bạn có thể gọi hàm tạo riêng tư tại đây). Xấu xí nhưng bạn có thể cung cấp cho trường một tên để truyền đạt ý định của bạn (JUST_TO_SILENCE_COBERTURA là một tên tốt).

  3. Bạn có thể để thử nghiệm của mình mở rộng lớp trợ giúp. Điều đó thực chất sẽ gọi hàm tạo mặc định nhưng lớp trình trợ giúp của bạn không thể là final nữa.

Tôi đề xuất phương pháp cuối cùng đặc biệt là vì lớp học không thể là final nữa. Nếu một người tiêu dùng mã của bạn muốn thêm một phương thức trợ giúp khác, bây giờ họ có thể mở rộng lớp hiện có và nhận một xử lý để tới tất cả các phương thức trợ giúp. Điều này tạo ra một sự kết hợp của các phương pháp helper mà truyền đạt ý định (những thuộc về nhau) - đó là không thể nếu lớp helper là final

Nếu bạn muốn ngăn chặn người dùng vô tình nhanh chóng lớp helper, làm cho nó abstract thay vì sử dụng một hàm tạo ẩn.

+1

Cách tiếp cận thứ ba theo ý kiến ​​của tôi là tốt nhất, vì nó không ảnh hưởng đến mã (chỉ kiểm tra). Tôi sẽ đi theo cách này. Cảm ơn bạn đã giúp đỡ. –

2

số

Trừ khi bạn gọi hàm tạo riêng (rõ ràng là mã xấu), bạn sẽ không thể bao gồm các dòng đó.

7

Đạt được mức độ phù hợp 100% trong mọi trường hợp, nhưng có một số trường hợp không thể thực hiện được điều này. Tất nhiên nếu bạn có một lớp mà không bao giờ được khởi tạo, Cobertura sẽ nhận được điều này như là một phạm vi kiểm tra không hoàn chỉnh, bởi vì những dòng mã thực sự trong lớp, nhưng chúng không được thử nghiệm.

Sự thật là bạn sẽ không bao giờ gọi một hàm tạo riêng tư (tôi giả sử bạn đã ẩn hàm tạo bằng cách đặt nó ở chế độ riêng tư), vì vậy tôi sẽ không bận tâm. Thử nghiệm phải là về việc bạn đang mong đợi điều gì và trong khi tôi đồng ý mức độ phù hợp 100% là tốt, trong một số trường hợp (như thế này) điều này không hữu ích.

Hãy xem 100% Code Coverage.

+2

Đôi khi yêu cầu bảo hành mã từ cấp quản lý cấp cao nhất (trong trường hợp này là), vì vậy đối với tôi có được 100% cho lớp cụ thể này là khá hữu ích. Và vâng - tôi nhận thức được sự lố bịch của cách tiếp cận này. Tuy nhiên - cảm ơn bạn đã liên kết cho bài viết. –

27

Nếu bạn hoàn toàn cần đạt được phạm vi mã 100% - giá trị của điều đó có thể được tranh luận ở nơi khác :) - bạn có thể đạt được nó bằng cách sử dụng sự phản ánh trong các thử nghiệm của bạn. Theo thói quen, khi tôi thực hiện một lớp tiện ích tĩnh chỉ, tôi thêm vào một hàm tạo riêng để đảm bảo rằng các thể hiện của lớp không thể được tạo ra. Ví dụ:

/** 
* Constructs a new MyUtilities. 
* @throws InstantiationException 
*/ 
private MyUtilities() throws InstantiationException 
{ 
    throw new InstantiationException("Instances of this type are forbidden."); 
} 

Sau đó, kiểm tra của bạn có thể trông giống như thế này:

@Test 
public void Test_Constructor_Throws_Exception() throws IllegalAccessException, InstantiationException { 
    final Class<?> cls = MyUtilties.class; 
    final Constructor<?> c = cls.getDeclaredConstructors()[0]; 
    c.setAccessible(true); 

    Throwable targetException = null; 
    try { 
     c.newInstance((Object[])null); 
    } catch (InvocationTargetException ite) { 
     targetException = ite.getTargetException(); 
    } 

    assertNotNull(targetException); 
    assertEquals(targetException.getClass(), InstantiationException.class); 
} 

Về cơ bản, những gì bạn đang làm ở đây là nhận lớp theo tên, tìm kiếm các nhà thầu trên rằng kiểu lớp, thiết lập nó cho công chúng (gọi setAccessible), gọi hàm khởi tạo mà không có đối số, và sau đó đảm bảo rằng ngoại lệ đích được ném là InstantiationException.

Dù sao, như bạn đã nói, yêu cầu bao phủ mã 100% ở đây là một nỗi đau, nhưng có vẻ như nó nằm ngoài tầm tay bạn, vì vậy bạn có thể thực hiện rất ít. Tôi đã thực sự sử dụng cách tiếp cận tương tự như ở trên trong mã của riêng tôi, và tôi đã tìm thấy nó có lợi, nhưng không phải từ một quan điểm thử nghiệm. Thay vào đó, nó chỉ giúp tôi tìm hiểu thêm một chút về sự phản chiếu mà tôi biết trước đây :)

+1

+1 Đẹp hack :-) –

+0

+1, giải pháp thông minh! – JW8

+0

Tại sao 'hiện diện' trở lại trong khối catch? Bài kiểm tra sẽ luôn trả về đúng sự thật. ;) –

Các vấn đề liên quan