2010-09-01 38 views
6

我正在测试某个类。这个类在内部实例化一个“GetMethod”对象,该对象被传递给被注入到被测试类中的“HttpClient”对象。我正在嘲笑“HttpClient”类,但我需要修改“GetMethod”类的一个方法的行为。我在玩ArgumentCaptor,但我似乎无法在“何时”调用中获得实例化对象。在Mockito中捕获一个参数

例子:

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)); 

响应:

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() 

回答

4

好的,这就是我解决它的方法。有点复杂,但找不到任何其他方式。

在测试类:

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

您在编辑我的答案时发布了它。那么,我们都以同样的方式解决它:) – amorfis 2010-09-02 15:59:01

+0

是的,我找不到任何其他方式使用可用的工具。令人讨厌的黑客:)但它的工作时,它岩石! – 2010-09-02 23:06:43

12

你不能使用上getMethod when,因为getMethod不是模仿。它仍然是你的班级创建的真实对象。

ArgumentCaptor具有完全不同的目的。检查section 15 here

你可以让你的代码更具可测性。通常,创建其他类的新实例的类很难测试。把一些工厂放到这个类中来创建get/post方法,然后在测试这个工厂的模拟器,并且使它变成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 
    } 
} 

然后测试,你可以这样做:

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)); 

UPDATE

您也可以尝试一些讨厌的黑客攻击,并Answer和访问GetMethod的私处;)通过反射。 (这真是令人讨厌的黑客)

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

我知道实例化,使类很难测试,但在这种情况下,工厂将是矫枉过正,我不得随意更改实施太多。 – 2010-09-02 09:39:07