2016-02-18 5 views
2

Код, который я тестирую, работает правильно, журналы правильные.Mockito - Не удалось инициализировать Spy на HttpEntity


Тесты по ошибке: ConnectorTest: Не удалось инициализировать @Spy аннотированный поле 'объект'.


  • Почему я не могу использовать проверить на HTTP лица?
  • Есть ли лучший способ проверить его? Должен ли я следить за журналами в противном случае?

КЛАСС быть испытанным:

public class Connector { 

    private static final String hostname = "localhost"; 
    private int varnishPort = 8000; 

    private int connectionTimeout = 5000; //millis 
    private int requestTimeout = 5000; 
    private int socketTimeout = 5000; 

    private final HttpHost host; 
    private HttpClient httpClient; 
    private HttpEntity entity; 
    private HttpResponse response; 

    public Connector(){ 

     host = new HttpHost(this.hostname, this.varnishPort); 

     RequestConfig.Builder requestBuilder = RequestConfig.custom(); 
     requestBuilder = requestBuilder.setConnectTimeout(connectionTimeout); 
     requestBuilder = requestBuilder.setConnectionRequestTimeout(requestTimeout); 
     requestBuilder = requestBuilder.setSocketTimeout(socketTimeout); 

     HttpClientBuilder builder = HttpClientBuilder.create();  
     builder.setDefaultRequestConfig(requestBuilder.build()); 
     httpClient = builder.build(); 
    } 


    public void invalidateVarnishCache(String level, String idDb) { 

     try{ 
      String xPurgeRegex = level+"/"+idDb+"$"; 
      Header header = new BasicHeader("X-Purge-Regex", xPurgeRegex); 
      BasicHttpRequest purgeRequest = new BasicHttpRequest("PURGE", "/"); 
      purgeRequest.setHeader(header); 

      response = httpClient.execute(host, purgeRequest); 

      entity = response.getEntity(); 

      int statusCode = response.getStatusLine().getStatusCode(); 

      if(statusCode >= 300){ 

       int respLength = entity.getContent().available(); 
       byte[] errorResp = new byte[ respLength ]; 
       entity.getContent().read(errorResp, 0, respLength); 
       // log error 
      }else{ 
       // log success 
      } 

      EntityUtils.consume(entity); 

     }catch(Exception e){ 
      // log exception 
     } 
    } 

} 

MY TEST:

@RunWith(MockitoJUnitRunner.class) 
public class ConnectorTest { 

    @Mock 
    private HttpClient httpClient; 

    // @Spy 
    // private HttpEntity entity; 

    @InjectMocks 
    private Connector varnishPurger = new Connector(); 


    @Test 
    public void purgeFail() throws Exception{ 

     HttpResponse response500 = new BasicHttpResponse(new ProtocolVersion("HTTP/1.1", 0, 0), 500, "NO!_TEST"); 
     HttpEntity entity500 = new StringEntity("BAD entity. [test]"); 
     response500.setEntity(entity500); 

     doReturn(response500) 
     .when(httpClient).execute(isA(HttpHost.class), isA(BasicHttpRequest.class)); 

     varnishPurger.invalidateVarnishCache("level_test_500", "id_test_500"); 

     // verify(entity, times(1)).getContent().available(); // HOW DO I MAKE THIS WORK? 
    } 

    ... 

} 
+2

HttpEntity приведен, вероятно, интерфейс, поэтому шпионить было бы бессмысленно (как интерфейс не делает ничего). Извините, если это так. См. Http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Spy.html для вещей, которые Mockito не может заглядывать автоматически (вы могли бы поставить там реализующий класс, например, через 'private HttpEntity entity = новый MyEntityImpl(); ', который должен работать) –

+0

Пожалуйста, избегайте документации кода Google и используйте ссылки doc из github;) => http://site.mockito.org/mockito/docs/1.10.19/org/mockito/ Mockito.html – Brice

ответ

5

HttpEntity представляет собой интерфейс, он не может быть прослежена только издевались. Так что просто изменить аннотацию с @Mock, или другой вариант объявить инициализируется экземпляр:

@Spy HttpEntity entity = new BasicHttpEntity(); 

Во всяком случае, сообщение исключением довольно ясно, почему это происходит:

org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'entity'. 
Type 'HttpEntity' is an interface and it cannot be spied on. 

    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl$1.withBefores(JUnit45AndHigherRunnerImpl.java:27) 
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:276) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) 
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) 
Caused by: org.mockito.exceptions.base.MockitoException: Type 'HttpEntity' is an interface and it cannot be spied on. 
    ... 21 more 

Такое поведение совпадает с Mockito.spy(Object) , этот метод не может быть вызван, если нет экземпляра. Однако последние Mockito.spy(Class) не жалуются на это. Это может быть функциональность, которая не была перенесена в подсистему аннотаций.

Тем не менее семантически неправильно шпионить за интерфейсом, поскольку он не имеет поведения.

+0

Право. Мейвен просто дал мне короткую версию. Мое намерение в любом случае заключается в том, чтобы шпионить за реальной HttpEntity, которую я тестирую, чтобы издеваться над реальным HttpClient и HttpResponse, возможно ли это как-то? –

+0

Я могу в конечном итоге использовать отражение .. –

+0

@GaSacchi Я не следую точно намерениям тестирования, но почему бы не настроить макет ответа HTTP, чтобы вернуть spied 'BasicHttpEntity'? – Brice

0

Я решил так:

class MockHttpEntity implements HttpEntity{ 

    String msg = "Test_"; 
    InputStream inps; 
    int count = 0; 

    public MockHttpEntity(String msg){ 
     this.msg += msg; 
     inps = IOUtils.toInputStream(this.msg); 
    } 

    @Override 
    public InputStream getContent(){ 
     System.out.println("\n"+(++count)+") Mocked getContent() called.\n"); 
     return inps; 
    } 

    public int times(){ 
     return count; 
    } 

    @Override public void  consumeContent(){ } 
    @Override public Header  getContentEncoding(){ return null; } 
    @Override public long  getContentLength(){ return 0; } 
    @Override public Header  getContentType(){ return null;} 
    @Override public boolean isChunked(){ return false; } 
    @Override public boolean isRepeatable(){ return false; } 
    @Override public boolean isStreaming(){ return false; } 
    @Override public void  writeTo(OutputStream outstream){ } 
} 


@RunWith(MockitoJUnitRunner.class) 
public class ConnectorTest {  

    @Mock 
    private HttpClient httpClient; 

    @InjectMocks 
    private Connector varnishPurger = new Connector(); 


    @Test 
    public void purgeFailureResponse() throws Exception{ 

     MockHttpEntity mockedHttpEntity = new MockHttpEntity("bad entity"); 

     HttpResponse response500 = new BasicHttpResponse(new ProtocolVersion("HTTP/1.1", 0, 0), 500, "NO!_TEST"); 
     response500.setEntity(mockedHttpEntity); 

     doReturn(response500) 
     .when(httpClient).execute(isA(HttpHost.class), isA(BasicHttpRequest.class)); 

     varnishPurger.invalidateVarnishCache("level_test_no", "id_test_no"); 

     Assert.assertTrue(mockedHttpEntity.times() == 2); 
    } 
    ... 
} 
Смежные вопросы