2010-09-01 2 views
6

Tôi đang thử một lớp nhất định. Lớp này là nội bộ instantiating một "GetMethod" đối tượng được truyền cho một "HttpClient" đối tượng được tiêm vào lớp thử nghiệm.Ghi lại một đối số trong Mockito

Tôi đang chế nhạo lớp "HttpClient", nhưng tôi sẽ cần phải sửa đổi hành vi của một phương thức của lớp "GetMethod". Tôi đang chơi với ArgumentCaptor nhưng tôi dường như không thể có được một tổ chức của đối tượng instantiated trong "khi" cuộc gọi.

Ví dụ:

HttpClient mockHttpClient = mock(HttpClient.class); 
ArgumentCaptor<GetMethod> getMethod = ArgumentCaptor.forClass(GetMethod.class); 
when(mockHttpClient.executeMethod(getMethod.capture())).thenReturn(HttpStatus.SC_OK); 
when(getMethod.getValue().getResponseBodyAsStream()).thenReturn(new FileInputStream(source)); 

đáp ứng:

org.mockito.exceptions.base.MockitoException: 
No argument value was captured! 
You might have forgotten to use argument.capture() in verify()... 
...or you used capture() in stubbing but stubbed method was not called. 
Be aware that it is recommended to use capture() only with verify() 

Trả lời

4

Ok, đây là cách tôi đã giải quyết nó. Một chút phức tạp nhưng không thể tìm thấy bất kỳ cách nào khác.

Trong lớp thử nghiệm:

private GetMethod getMethod; 

public void testMethod() { 
    when(mockHttpClient.executeMethod(any(GetMethod.class))).thenAnswer(new ExecuteMethodAnswer()); 
    //Execute your tested method here. 
    //Acces the getMethod here, assert stuff against it. 
} 

private void setResponseStream(HttpMethodBase httpMethod, InputStream inputStream) throws NoSuchFieldException, IllegalAccessException { 
    Field privateResponseStream = HttpMethodBase.class.getDeclaredField("responseStream"); 
    privateResponseStream.setAccessible(true); 
    privateResponseStream.set(httpMethod, inputStream); 
} 

private class ExecuteMethodAnswer implements Answer { 
    public Object answer(InvocationOnMock invocation) throws FileNotFoundException, 
                  NoSuchFieldException, IllegalAccessException { 
     getMethod = (GetMethod) invocation.getArguments()[0]; 
     setResponseStream(getMethod, new FileInputStream(source)); 
     return HttpStatus.SC_OK; 
    } 
} 
+0

Bạn đã đăng nó khi tôi đang chỉnh sửa câu trả lời của mình. Vâng, cả hai chúng tôi đã giải quyết nó theo cách tương tự :) – amorfis

+0

Có, tôi không thể tìm thấy bất kỳ cách nào khác để làm điều đó với các công cụ có sẵn. Nasty hack :) nhưng nó đá khi nó hoạt động! –

12

Bạn không thể sử dụng when trên GetMethod, vì GetMethod không phải là một mô hình. Nó vẫn là đối tượng thực sự được tạo ra bởi lớp học của bạn.

ArgumentCaptor có mục đích khá khác nhau. Kiểm tra section 15 here.

Bạn có thể làm cho mã của mình dễ kiểm tra hơn. Nói chung, các lớp học đang tạo các phiên bản mới của các lớp khác rất khó để kiểm tra. Đặt một số nhà máy vào lớp này để tạo các phương thức get/post, sau đó thử nghiệm nhà máy này, và làm cho nó giả lập các phương thức get/post.

public class YourClass { 
    MethodFactory mf; 

    public YourClass(MethodFactory mf) { 
    this.mf = mf; 
    } 

    public void handleHttpClient(HttpClient httpClient) { 
    httpClient.executeMethod(mf.createMethod()); 
    //your code here 
    } 
} 

Sau đó, trong bài kiểm tra bạn có thể làm:

HttpClient mockHttpClient = mock(HttpClient.class); 
when(mockHttpClient.executeMethod(any(GetMethod.class)).thenReturn(HttpStatus.SC_OK); 

MethodFactory factory = mock(MethodFactory.class); 
GetMethod get = mock(GetMethod.class); 
when(factory.createMethod()).thenReturn(get); 
when(get.getResponseBodyAsStream()).thenReturn(new FileInputStream(source)); 

CẬP NHẬT

Bạn cũng có thể thử một số hack khó chịu, và Answer và truy cập các phần riêng GetMethod của;) bằng cách phản chiếu. (Điều này thực sự khó chịu hack)

when(mockHttpClient.executeMethod(any(GetMethod.class))).thenAnswer(new Answer() { 
    Object answer(InvocationOnMock invocation) { 
    GetMethod getMethod = (GetMethod) invocation.getArguments()[0]; 

    Field respStream = HttpMethodBase.class.getDeclaredField("responseStream"); 
    respStream.setAccessible(true); 
    respStream.set(getMethod, new FileInputStream(source)); 

    return HttpStatus.SC_OK; 
    } 
}); 
+0

Tôi biết instantiation làm cho các lớp học khó khăn để kiểm tra, nhưng trong trường hợp này một nhà máy sẽ là quá mức cần thiết, và tôi không được tự do thay đổi việc thực hiện quá nhiều. –