我正在测试某个类(class)。该类在内部实例化“GetMethod”对象,该对象传递给“HttpClient”对象,该对象被注入(inject)到测试的类中。
我在 mock “HttpClient”类,但是我也需要修改“GetMethod”类的一种方法的行为。我正在与ArgumentCaptor一起玩,但似乎无法在“when”调用中保留实例化的对象。
例子:
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()
最佳答案
您不能在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));
更新
您还可以尝试进行一些讨厌的修改,并添加
Answer
并通过反射访问GetMethod的私有(private)部分;)。 (这真是令人讨厌的骇客)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;
}
});