2011-12-14 2 views
19

Tôi có một người thợ xây:Làm thế nào để chế giễu một người thợ xây với Mockito

class Builder{ 
    private String name; 
    private String address; 
    public Builder setName(String name){ 
     this.name = name; 
     return this; 
    } 
    public Builder setAddress(String address){ 
     this.address = address; 
     return this; 
    } 

} 

Mocking những người xây dựng ở Mockito sẽ mang lại cho tôi null cho mọi phương pháp. Vì vậy, có một cách dễ dàng để có được các nhà xây dựng trở lại chính nó trên mỗi cuộc gọi chức năng, mà không chế nhạo mọi chức năng chính nó bằng cách sử dụng when().thenReturn.

+2

Bạn có thực sự cần chế bản này không? Nó không giống như loại phụ thuộc đáng để chế giễu. Nó giống như một loại "dữ liệu" của lớp, chứ không phải là một loại "dịch vụ" của lớp. Tôi hiếm khi tìm thấy nó hữu ích để làm cho các lớp học mà không có nhiều hành vi thực tế. –

+1

Nó chỉ là một ví dụ, người xây dựng thực sự là một chút phức tạp hơn và nó chỉ không cần phải kiểm tra trong trường hợp này. –

+1

Bạn có thể tách chúng để bạn * có * có một "người xây dựng câm" (không cần chế nhạo) và sau đó phần dịch vụ * có * cần chế nhạo? –

Trả lời

8

Bạn có thể sử dụng RETURN_DEEP_STUBS để tạo chuỗi chuỗi.

Nếu bạn biết thứ tự chính xác xây dựng của bạn sẽ được gọi, đây là một ví dụ về cách bạn sẽ sử dụng nó:

Builder b = Mockito.mock(Builder.class, RETURNS_DEEP_STUBS); 
when(b.setName("a name").setAddress("an address")).thenReturn(b); 
assert b.setName("a name").setAddress("an address") == b; // this passes 

Đáng tiếc là điều này sẽ không cung cấp cho bạn một cách chung chung của chế giễu "tất cả các nhà xây dựng khác nhau phương pháp "để họ luôn luôn trả lại điều này, xem câu trả lời khác là bạn cần điều đó.

+2

Ngoài ra NB rằng nếu bạn nhận được đặt hàng sâu "sai" và đúc kết quả, nó sẽ cung cấp cho bạn một số thông điệp tìm kiếm kỳ lạ, có thể giống như 'java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer $ ClassWithSuperclassToWorkAroundCglibBug $$ EnhancerByMockitoWithCGLIB $$ 851828bd không thể truyền sang ... ' – rogerdpack

34

Sự cố khi sử dụng RETURN_DEEP_STUBS là bạn sẽ nhận được một mô hình khác mỗi lần bạn gọi một phương thức. Tôi nghĩ từ câu hỏi của bạn rằng bạn muốn sử dụng Câu trả lời mặc định thực sự trả về mô hình mà nó được gọi, cho mỗi phương thức có kiểu trả về đúng. Điều này có thể trông giống như sau. Lưu ý rằng tôi đã không thử nghiệm này, vì vậy nó có thể chứa lỗi chính tả, nhưng tôi hy vọng rằng ý định rõ ràng trong mọi trường hợp.

import static org.mockito.Mockito.RETURNS_DEFAULTS; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class SelfReturningAnswer implements Answer<Object>{ 

    public Object answer(InvocationOnMock invocation) throws Throwable { 
     Object mock = invocation.getMock(); 
     if(invocation.getMethod().getReturnType().isInstance(mock)){ 
      return mock; 
     } 
     else{ 
      return RETURNS_DEFAULTS.answer(invocation); 
     } 
    } 
} 

Sau đó, khi bạn tạo mô hình, hãy chỉ định đây làm câu trả lời mặc định của bạn. Điều này sẽ làm cho giả của bạn trở lại chính nó từ mỗi phương pháp mà nó có thể; nhưng nó sẽ hoạt động như một mô hình thông thường khi bạn gọi một phương thức có kiểu trả về là sai đối với mô hình.

Tạo mô hình của bạn như thế này

Builder mockBuilder = mock(Builder.class, new SelfReturningAnswer()); 

hoặc tạo một hằng số cho lớp này và viết một cái gì đó giống như

@Mock(answer = SELF_RETURNING) private Builder mockBuilder; 

Hy vọng rằng sẽ giúp.

+0

Bạn có chắc chắn không. Tôi sử dụng ´verify 'trên mô hình sâu thối rữa của tôi và nó vượt qua các bài kiểm tra. Vì vậy, nó phải trả về cùng một cá thể mỗi khi tôi sử dụng một phương thức xây dựng. –

+1

Vâng, tôi hoàn toàn chắc chắn.Tôi đã viết một bài kiểm tra cho lớp Builder của bạn, như ở trên, nơi tôi đã tạo một mô hình với RETURNS_DEEP_STUBS, sau đó được gọi là setAddress và setName. Thử nghiệm của tôi khẳng định rằng hai mocks trở lại từ hai cuộc gọi phương thức là khác nhau. Thử nghiệm của tôi đã trôi qua. –

+0

Bài kiểm tra của tôi là http://pastebin.com/JNPrn4ng –

12

Kể từ Mockito 2.0 (beta), có một câu trả lời mặc định mới cho RETURNS_SELF hoạt động gần như giống hệt với David Wallace's answer. Ví dụ từ các tài liệu Mockito:

@Test 
public void use_full_builder_with_terminating_method() { 
    HttpBuilder builder = mock(HttpBuilder.class, RETURNS_SELF); 
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder); 
    String response = "StatusCode: 200"; 

    when(builder.request()).thenReturn(response); 

    assertThat(requester.request("URI")).isEqualTo(response); 
} 

Lưu ý rằng nó xuất hiện cả trên lớp Mockito và trên Answers enum, vì vậy nó cũng tương thích với @Mock(answer = RETURNS_SELF) cú pháp.