2009-01-08 42 views
8

Rất nhiều nhà phát triển cho rằng thử nghiệm các phương pháp riêng tư là một ý tưởng tồi. Tuy nhiên, tất cả các ví dụ tôi đã tìm thấy dựa trên ý tưởng rằng các phương thức riêng tư là riêng tư bởi vì gọi chúng có thể phá vỡ trạng thái của đối tượng bên trong. Nhưng đó không chỉ là lý do để ẩn phương pháp.Phương pháp riêng thử nghiệm đơn vị: Mẫu mặt tiền

Hãy xem xét Mẫu mặt tiền. Người dùng lớp của tôi cần 2 phương thức công khai. Chúng sẽ quá lớn. Trong ví dụ của tôi, họ cần tải một số cấu trúc phức tạp từ BLOB của cơ sở dữ liệu, phân tích nó, điền một số đối tượng COM tạm thời, chạy macro của người dùng để xác nhận hợp lệ và sửa đổi các đối tượng này, và sắp xếp các đối tượng đã sửa đổi thành XML. Khá lớn chức năng cho metod duy nhất :-) Hầu hết các hành động này là cần thiết cho cả hai phương pháp công cộng. Vì vậy, tôi đã tạo ra khoảng 10 phương pháp riêng và 2 phương pháp công khai gọi chúng. Trên thực tế, phương pháp riêng tư của tôi không nhất thiết phải là riêng tư; họ sẽ không phá vỡ trạng thái bên trong của ví dụ. Tuy nhiên, khi tôi không wont thử nghiệm phương pháp riêng, tôi có những vấn đề sau đây:

  1. Xuất bản họ có nghĩa là phức tạp cho người dùng (họ có một sự lựa chọn họ không cần)
  2. Tôi không thể tưởng tượng phong cách TDD cho một phương pháp công khai lớn như vậy, khi bạn viết 500 + dòng mã chỉ để trả về một cái gì đó (thậm chí không phải là kết quả thực).
  3. Dữ liệu cho các phương pháp này được truy xuất từ ​​cơ sở dữ liệu và việc thử nghiệm chức năng liên quan đến DB khó khăn hơn nhiều.

Khi tôi đang thử nghiệm phương pháp riêng:

  1. tôi không công bố chi tiết đó sẽ khiến người dùng. Giao diện công cộng bao gồm 2 phương thức.
  2. Tôi có thể làm việc theo kiểu TDD (viết các phương thức nhỏ theo từng bước).
  3. Tôi có thể bao gồm hầu hết các chức năng của lớp bằng cách sử dụng dữ liệu thử nghiệm, không có kết nối cơ sở dữ liệu.

Ai đó có thể mô tả, tôi đang làm gì sai? Tôi nên sử dụng thiết kế nào để có được cùng một khoản tiền thưởng và không thử nghiệm các phương pháp riêng tư?

CẬP NHẬT: Dường như với tôi tôi đã trích xuất tất cả mọi thứ tôi đã có thể đến các lớp khác. Vì vậy, tôi không thể tưởng tượng những gì tôi có thể trích xuất bổ sung. Việc tải từ cơ sở dữ liệu được thực hiện bởi lớp ORM, phân tích luồng, tuần tự hóa thành XML, chạy macro - mọi thứ được thực hiện bởi các lớp độc lập. Lớp này chứa cấu trúc dữ liệu khá phức tạp, các thường trình để tìm kiếm và chuyển đổi, và các cuộc gọi cho tất cả các tiện ích đã đề cập. Vì vậy, tôi không nghĩ rằng cái gì khác có thể được trích xuất; nếu không, trách nhiệm của nó (kiến thức về cấu trúc dữ liệu) sẽ được chia giữa các lớp. Vì vậy, phương pháp tốt nhất để giải quyết mà tôi thấy bây giờ là chia thành 2 đối tượng (Mặt tiền và đối tượng thực, với phương thức riêng trở thành công khai) và di chuyển đối tượng thực đến đâu đó không ai cố gắng tìm nó. Trong trường hợp của tôi (Delphi) nó sẽ là một đơn vị độc lập, trong các ngôn ngữ khác nó có thể là một không gian tên riêng biệt. Tùy chọn tương tự khác là 2 giao diện, cảm ơn ý tưởng.

+1

Có vẻ như đã có một câu hỏi giống hệt với câu hỏi này: http://stackoverflow.com/questions/250692/how-do-you- unit-test-private-methods –

+0

Không có nó không phải là một dupe – krosenvold

+0

Đây là blog về thử nghiệm phương pháp riêng trong C# http: //www.coolaspdotnetcode.com/Web/NunitTesting-testingprivatemethod.aspx – Shiva

Trả lời

17

Tôi nghĩ rằng bạn đang đặt quá nhiều trách nhiệm (triển khai) vào mặt tiền. Tôi thường xem đây là một front-end cho việc triển khai thực tế trong các lớp khác.

Vì vậy, các phương pháp riêng trong mặt tiền của bạn có thể là phương pháp công khai trong một hoặc nhiều lớp khác. Sau đó, bạn có thể kiểm tra chúng ở đó.

+0

Xem cập nhật, vui lòng. Trách nhiệm của lớp này là giữ cấu trúc dữ liệu khá phức tạp và các thói quen để thực hiện tìm kiếm, chuyển đổi, vv Mọi thứ khác được trích xuất ở bên ngoài. Vì vậy, bản thân mặt tiền có thể được trích xuất, nhưng tôi không nghĩ rằng bất cứ điều gì khác có thể được trích xuất quá. – Abelevich

3

Phương pháp riêng được sử dụng để đóng gói một số hành vi không có ý nghĩa bên ngoài lớp bạn đang cố gắng kiểm tra.Bạn không bao giờ phải thử nghiệm các phương thức riêng vì chỉ có các phương thức công cộng hoặc được bảo vệ của cùng một lớp sẽ gọi các phương thức riêng.

Nó có thể chỉ là lớp học của bạn rất phức tạp và sẽ mất nhiều công sức để kiểm tra nó. Tuy nhiên, tôi sẽ đề nghị bạn tìm kiếm các trừu tượng mà bạn có thể đột nhập vào các lớp học của riêng họ. Các lớp này sẽ có phạm vi nhỏ hơn của các mục và độ phức tạp để kiểm tra.

2

Tôi không quen với yêu cầu của bạn & thiết kế nhưng có vẻ như thiết kế của bạn là thủ tục chứ không phải là hướng đối tượng. tức là bạn có 2 phương pháp công khai và nhiều phương pháp riêng tư. Nếu bạn chia lớp của bạn thành các đối tượng mà mỗi đối tượng có vai trò của nó thì sẽ dễ dàng hơn để kiểm tra từng lớp "nhỏ". Ngoài ra, bạn có thể đặt cấp độ truy cập đối tượng "người trợ giúp" cho gói (mặc định trong Java, tôi biết có mức truy cập tương tự trong C#) theo cách này bạn không hiển thị chúng trong API nhưng bạn có thể kiểm tra chúng một cách độc lập (như họ là đơn vị).

4

Ai đó có thể mô tả, tôi là gì làm sai?

Có thể không có gì?

Nếu tôi muốn thử nghiệm một phương pháp tôi đặt nó làm phạm vi (gói) mặc định và kiểm tra nó.

Bạn đã đề cập một giải pháp tốt khác: tạo giao diện với hai phương pháp của bạn. Khách hàng của bạn truy cập vào hai phương thức đó và khả năng hiển thị của các phương thức khác không quan trọng.

2

Có thể nếu bạn mất thời gian và tìm kiếm Clean Code Tech talks từ Miško. Anh ta rất thấu đáo về cách viết mã để được kiểm tra.

2

Đây là một chủ đề gây nhiều tranh cãi ... Hầu hết TDDers giữ ý kiến ​​rằng việc tái cấu trúc các phương pháp của bạn để kiểm tra đơn vị dễ dàng hơn thực sự làm cho thiết kế của bạn tốt hơn. Tôi nghĩ rằng điều này thường đúng, nhưng trường hợp cụ thể của các phương thức riêng cho các API công cộng chắc chắn là một ngoại lệ. Vì vậy, có, bạn nên thử nghiệm phương pháp riêng tư, và không, bạn không nên làm cho nó công khai.

Nếu bạn đang làm việc trong Java, đây là một phương pháp hữu ích, tôi đã viết rằng sẽ giúp bạn kiểm tra các phương pháp private static trong một lớp học:

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import junit.framework.Assert; 

public static Object invokeStaticPrivateMethod(Class<?> clazz, String methodName, Object... params) { 
    Assert.assertNotNull(clazz); 
    Assert.assertNotNull(methodName); 
    Assert.assertNotNull(params); 

    // find requested method 
    final Method methods[] = clazz.getDeclaredMethods(); 
    for (int i = 0; i < methods.length; ++i) { 
     if (methodName.equals(methods[i].getName())) { 
      try { 
       // this line makes testing private methods possible :) 
       methods[i].setAccessible(true); 
       return methods[i].invoke(clazz, params); 
      } catch (IllegalArgumentException ex) { 
       // maybe method is overloaded - try finding another method with the same name 
       continue; 
      } catch (IllegalAccessException ex) { 
       Assert.fail("IllegalAccessException accessing method '" + methodName + "'"); 
      } catch (InvocationTargetException ex) { 
       // this makes finding out where test failed a bit easier by 
       // purging unnecessary stack trace 
       if (ex.getCause() instanceof RuntimeException) { 
        throw (RuntimeException) ex.getCause(); 
       } else { 
        throw new InvocationException(ex.getCause()); 
       } 
      } 
     } 
    } 

    Assert.fail("method '" + methodName + "' not found"); 
    return null; 
} 

này có thể có thể được viết lại cho các phương pháp không tĩnh là tốt, nhưng những phương pháp riêng tư pesky thường là riêng tư nên tôi không bao giờ cần điều đó. :)

2

giả sử bạn có 8 phương thức riêng và 2 phương thức công khai. Nếu bạn có thể thực hiện một phương thức riêng một cách độc lập, tức là mà không cần gọi bất kỳ phương pháp nào khác và không có tác dụng phụ của tiểu bang bị lỗi thì đơn vị thử nghiệm chỉ là phương pháp có ý nghĩa. Nhưng sau đó trong trường hợp đó không có nhu cầu cho các phương pháp để được tư nhân!

trong C# tôi sẽ làm cho các phương pháp như bảo vệ thay vì tư nhân, và phơi bày chúng như nào trong một lớp con để thử nghiệm

cho kịch bản của bạn, nó có thể có ý nghĩa hơn đối với các phương pháp kiểm chứng được công khai và cho phép người dùng có mặt tiền thực với chỉ 2 phương thức công khai mà họ cần cho giao diện của họ

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