2010-09-01 5 views
6

Я тестирую определенный класс. Этот класс внутренне создает экземпляр объекта GetMethod, который передается объекту «HttpClient», который вводится в тестируемый класс.Захват аргумента в Mockito

Я издеваюсь над классом «HttpClient», но мне также нужно будет изменить поведение одного метода класса «GetMethod». Я играю с ArgumentCaptor, но, похоже, я не могу уловить экземпляр объекта в вызове «когда».

Пример:

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

+0

Да, я не могу найти другого способа сделать это с помощью доступных инструментов. Грязный хак :), но он скалывает, когда он работает! –

12

Вы не можете использовать when на getMethod, потому что 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

Я знаю, что конкретизация делает классы трудно проверить, но в этом случае завод будет излишним, и я не волен изменить реализацию слишком много. –

 Смежные вопросы

  • Нет связанных вопросов^_^