2012-01-10 37 views
55
 
public class A { 

    public void method(boolean b){ 
      if (b == true) 
       method1(); 
      else 
       method2(); 
    } 

    private void method1() {} 
    private void method2() {} 
} 
 
public class TestA { 

    @Test 
    public void testMethod() { 
     A a = mock(A.class); 
     a.method(true); 
     //how to test like verify(a).method1(); 
    } 
} 

Làm thế nào để kiểm tra phương pháp riêng được gọi là hay không, và làm thế nào để kiểm tra phương pháp tư nhân sử dụng Mockito ???Kiểm tra phương pháp cá nhân sử dụng Mockito

Trả lời

48

Bạn không thể làm điều đó với Mockito nhưng bạn có thể sử dụng Powermock để mở rộng phương thức riêng tư và giả lập Mockito. Powermock hỗ trợ Mockito. Here là một ví dụ.

+5

Tôi bối rối với câu trả lời này. Đây là chế nhạo, Nhưng tiêu đề đang thử nghiệm các phương thức riêng –

+0

Tôi đã sử dụng Powermock để thử phương pháp riêng, nhưng làm cách nào tôi có thể kiểm tra phương thức riêng với Powermock. Ở đâu, tôi có thể vượt qua một số đầu vào và mong đợi một số đầu ra từ phương pháp và sau đó xác minh đầu ra? – Rito

1

Đặt thử nghiệm của bạn trong cùng một gói, nhưng một thư mục nguồn khác (src/main/java so với src/test/java) và đặt các gói đó thành riêng tư. Khả năng kiểm tra Imo quan trọng hơn tính riêng tư.

+5

Lý do chính đáng duy nhất là kiểm tra một phần của hệ thống cũ.Nếu bạn bắt đầu thử nghiệm phương thức private/package-private, bạn phơi bày đối tượng bên trong của bạn. Làm như vậy thường dẫn đến mã tái cấu trúc kém. Thành phần PRefer để bạn có thể đạt được khả năng kiểm tra, với tất cả sự tốt lành của một hệ thống hướng đối tượng. – Brice

+0

Đồng ý - đó sẽ là cách ưa thích. Tuy nhiên, nếu bạn thực sự muốn thử nghiệm các phương thức riêng với mockito, đây là tùy chọn duy nhất (loại an toàn) mà bạn có. Câu trả lời của tôi là một chút vội vàng mặc dù, tôi nên đã chỉ ra những rủi ro, như bạn và những người khác đã làm điều đó. –

+0

Đây là cách ưa thích của tôi. Không có gì sai khi phơi bày đối tượng bên trong ở mức gói-tư nhân; và kiểm tra đơn vị là thử nghiệm hộp trắng, bạn cần biết nội bộ để thử nghiệm. –

91

Không thể thông qua mockito. Từ số wiki

Tại sao Mockito không thử phương pháp riêng tư?

Thứ nhất, chúng tôi không có ý kiến ​​về cách chế nhạo phương thức riêng tư. Chúng tôi chỉ không quan tâm đến phương pháp riêng tư vì từ quan điểm của thử nghiệm các phương pháp riêng tư không tồn tại. Dưới đây là một vài lý do Mockito không thử phương pháp riêng:

Nó đòi hỏi hack của classloaders mà không bao giờ là chống đạn và nó thay đổi api (bạn phải sử dụng runner thử nghiệm tùy chỉnh, chú thích các lớp, , vv).

Rất dễ làm việc xung quanh - chỉ cần thay đổi mức độ hiển thị của phương thức từ riêng tư sang gói được bảo vệ (hoặc được bảo vệ).

Nó yêu cầu tôi dành thời gian thực hiện & duy trì nó. Và nó không có ý nghĩa cho điểm # 2 và thực tế là nó đã được thực hiện trong công cụ khác nhau (powermock).

Cuối cùng ... Phương pháp riêng tư bí mật là một gợi ý rằng có điều gì đó sai với sự hiểu biết của OO. Trong OO bạn muốn các đối tượng (hoặc vai trò) để cộng tác, không phải phương thức. Quên về pascal & mã thủ tục. Hãy suy nghĩ trong các đối tượng.

4

Bạn không giả sử thử nghiệm các phương pháp riêng tư. Chỉ những phương pháp không phải riêng tư cần phải được kiểm tra vì chúng nên gọi phương thức riêng tư. Nếu bạn "muốn" thử nghiệm các phương pháp riêng tư, nó có thể cho thấy rằng bạn cần phải suy nghĩ lại về thiết kế của mình:

Tôi có đang sử dụng tiêm phụ thuộc thích hợp không? Tôi có thể cần phải di chuyển các phương thức riêng tư vào một lớp riêng biệt và thay vì kiểm tra điều đó? Các phương thức này có phải là riêng tư không? ... chúng không thể được mặc định hay được bảo vệ chứ?

Trong trường hợp trên, hai phương pháp được gọi là "ngẫu nhiên" có thể thực sự cần phải được đặt trong một lớp của riêng mình, được kiểm tra và sau đó được tiêm vào lớp ở trên.

+13

Điểm hợp lệ. Tuy nhiên, không phải là lý do để sử dụng một công cụ sửa đổi riêng cho các phương thức là vì bạn chỉ muốn cắt bớt các mã quá dài và/hoặc lặp đi lặp lại? Tách nó như một lớp khác giống như bạn đang quảng cáo những dòng mã đó là công dân hạng nhất sẽ không được sử dụng lại ở bất kỳ nơi nào khác bởi vì nó có nghĩa là phân vùng mã dài và ngăn chặn lặp lại các dòng mã. Nếu bạn định tách nó ra một lớp khác, nó không cảm thấy đúng; bạn sẽ dễ dàng bị nổ lớp. – supertonsky

+2

Supertonsky được chú ý, tôi đã đề cập đến trường hợp chung. Tôi đồng ý rằng trong trường hợp trên, nó không nên ở trong một lớp học riêng biệt. (+1 trên bình luận của bạn mặc dù - nó là một điểm rất hợp lệ bạn đang làm trên thúc đẩy các thành viên tư nhân) –

+1

@ superupersky, tôi đã không thể tìm thấy bất kỳ phản ứng thỏa đáng cho vấn đề này. Có một số lý do tại sao tôi có thể sử dụng các thành viên tư nhân và rất thường xuyên họ không chỉ ra một mùi mã và tôi sẽ được hưởng lợi rất nhiều từ việc kiểm tra chúng. Mọi người dường như đánh lừa điều này bằng cách nói "chỉ không làm điều đó". – LuddyPants

11

Hãy suy nghĩ về điều này về hành vi, chứ không phải về phương pháp có. Phương pháp được gọi là method có một hành vi cụ thể nếu b là đúng sự thật. Nó có hành vi khác nhau nếu b là sai. Điều này có nghĩa là bạn nên viết hai bài kiểm tra khác nhau cho method; một cho mỗi trường hợp.Vì vậy, thay vì có ba bài kiểm tra định hướng phương pháp (một cho method, một cho method1, một cho method2, bạn có hai bài kiểm tra theo định hướng hành vi. một từ bốn chữ cái như vậy, vì vậy hãy thoải mái sử dụng một hạt muối), tôi thấy hữu ích khi chọn các tên thử nghiệm phản ánh hành vi mà tôi đang thử nghiệm, chứ không phải tên của phương thức. Không gọi các xét nghiệm của bạn testMethod(), testMethod1(), testMethod2() và vân vân. Tôi thích các tên như calculatedPriceIsBasePricePlusTax() hoặc taxIsExcludedWhenExcludeIsTrue() cho biết tôi đang thử nghiệm hành vi nào, sau đó trong mỗi phương pháp thử nghiệm, chỉ kiểm tra hành vi được chỉ định. một phương pháp công khai, nhưng có thể liên quan đến nhiều c tất cả các phương pháp riêng tư.

Hy vọng điều này sẽ hữu ích.

+3

@mlvljr Nó không phải là quá nhiều về việc đặt tên, nhưng về đề nghị của tôi về việc thực hành viết một bài kiểm tra cho mỗi hành vi, chứ không phải là một bài kiểm tra cho mỗi phương pháp. Nhưng cảm ơn cười khúc khích! –

2

Tôi thực sự không hiểu nhu cầu của bạn để kiểm tra phương pháp riêng tư. Vấn đề gốc là phương thức công khai của bạn bị vô hiệu là kiểu trả về và do đó bạn không thể kiểm tra phương thức công khai của mình. Do đó bạn buộc phải kiểm tra phương pháp riêng của mình. Đoán của tôi có đúng không ??

Một vài giải pháp khả thi (AFAIK):

  1. Mocking phương pháp riêng của bạn, nhưng bạn vẫn sẽ không được "thực sự" thử nghiệm phương pháp của bạn.

  2. Xác minh trạng thái của đối tượng được sử dụng trong phương pháp. Phương pháp MOSTLY hoặc làm một số xử lý các giá trị đầu vào và trả về một đầu ra, hoặc thay đổi trạng thái của các đối tượng. Kiểm tra các đối tượng cho trạng thái mong muốn cũng có thể được sử dụng.

    public class A{ 
    
    SomeClass classObj = null; 
    
    public void publicMethod(){ 
        privateMethod(); 
    } 
    
    private void privateMethod(){ 
        classObj = new SomeClass(); 
    } 
    
    } 
    

    [Ở đây bạn có thể kiểm tra đối với phương pháp tư nhân, bằng cách kiểm tra sự thay đổi trạng thái của classObj từ null để không null.]

  3. Refactor mã của bạn một chút (Hy vọng đây là không phải là mã cũ). Funda của tôi viết một phương pháp là, một trong những nên luôn luôn trả lại một cái gì đó (một int/a boolean). Giá trị trả về CÓ THỂ hoặc KHÔNG THỂ được sử dụng bởi việc thực hiện, nhưng nó sẽ SURELY BE được sử dụng bởi các kiểm tra

    mã.

    public class A 
    { 
        public int method(boolean b) 
        { 
          int nReturn = 0; 
          if (b == true) 
           nReturn = method1(); 
          else 
           nReturn = method2(); 
        } 
    
        private int method1() {} 
    
        private int method2() {} 
    
    } 
    
15

Dưới đây là một ví dụ nhỏ làm thế nào để làm điều đó với powermock

public class Hello { 
    private Hello obj; 
    private Integer method1(Long id) { 
     return id + 10; 
    } 
} 

Để kiểm tra method1 đang sử dụng:

Hello testObj = new Hello(); 
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L)); 

Để thiết lập đối tượng tin obj sử dụng điều này:

Hello testObj = new Hello(); 
Hello newObject = new Hello(); 
Whitebox.setInternalState(testObj, "obj", newObject); 
+0

Tôi nghĩ đây là câu trả lời đúng. – Pranalee

+0

Liên kết của bạn chỉ trỏ đến repo giả điện @Mindaugas – Xavier

+0

@Xavier true. Bạn có thể sử dụng nó nếu bạn thích trong dự án của bạn. – Mindaugas

3

Tôi đã thử nghiệm phương thức riêng tư bên trong bằng cách sử dụng mockito khi sử dụng sự phản chiếu. Đây là ví dụ, đã cố gắng đặt tên cho nó sao cho có ý nghĩa

//Service containing the mock method is injected with mockObjects 

@InjectMocks 
private ServiceContainingPrivateMethod serviceContainingPrivateMethod; 

//Using reflection to change accessibility of the private method 

Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class}; 
    Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params); 
    //making private method accessible 
    m.setAccessible(true); 
    assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null)); 
Các vấn đề liên quan