7

特定のクラスをテストしています。このクラスは、テストされたクラスに注入される「HttpClient」オブジェクトに渡される「GetMethod」オブジェクトを内部的にインスタンス化しています。

「HttpClient」クラスをモックしていますが、「GetMethod」クラスの 1 つのメソッドの動作も変更する必要があります。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()
4

2 に答える 2

13

You cant use when on getMethod, because getMethod is not a mock. It is still real object created by your class.

ArgumentCaptor has quite different purpose. Check section 15 here.

You could make your code more testable. Generally, classes that are creating new instances of other classes are difficult to test. Put some factory to this class for creating get/post methods, then in test mock this factory, and make it mock get/post methods.

public class YourClass {
  MethodFactory mf;

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

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

Then in test you can do:

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

You can also try some nasty hack, and Answer and accessing GetMethod's private parts ;) by reflection. (This is really nasty 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;
  }
});
于 2010-09-01T22:18:35.907 に答える
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;
    }
}
于 2010-09-02T14:33:58.993 に答える