2012-06-12 13 views
25

Escribí un código que llama a la API del cliente de Jersey, que a su vez llama a un servicio web que está fuera de mi control. No quiero que mi prueba unitaria llame al servicio web real.¿Cómo puedo probar el código de unidad que llama a la API de Jersey Client?

¿Cuál es el mejor enfoque para escribir una prueba de unidad para el código que llama a la API de cliente de Jersey? ¿Debo usar la API del servidor Jersey para escribir un servicio web JAX-RS y luego usar el marco de prueba de Jersey para la prueba unitaria? ¿O debería burlarme de las llamadas al servicio web de Jersey? Tengo acceso a JMock. ¿O debería intentar otro enfoque?

Durante mi investigación, encontré this discussion describiendo varias opciones, pero encontré una solución completa. ¿Hay algún ejemplo de código disponible que muestre un enfoque sugerido de JUnit? No pude encontrar ninguno en la documentación de Jersey.

Aquí está el código fuente correspondiente:

public String getResult(URI uri) throws Exception { 
    // error handling code removed for clarity 
    ClientConfig clientConfig = new DefaultClientConfig(); 
    Client client = Client.create(clientConfig); 
    WebResource service = client.resource(uri); 
    String result = service.accept(accept).get(String.class); 
    return result; 
} 

Éstos son ejemplos de código de prueba que me gustaría pasar. Me gustaría probar (1) pasar un URI válido y recuperar una cadena válida y (2) pasar un URI inválido (por cualquier motivo, inalcanzable o no autorizado) y obtener una excepción.

@Test 
public void testGetResult_ValidUri() throws Exception { 
    String xml = retriever.getResult(VALID_URI); 
    Assert.assertFalse(StringUtils.isBlank(xml)); 
} 

@Test(expected = IllegalArgumentException.class) 
public void testGetResult_InvalidUri() throws Exception { 
    retriever.getResult(INVALID_URI); 
} 

Todo lo anterior es la descripción simple de lo que hace mi código. En realidad, hay una capa encima que acepta dos URI, primero intenta llamar al primer URI y, si ese URI falla, intenta llamar al segundo URI. Me gustaría tener pruebas unitarias que cubran (1) que el primer URI tenga éxito, (2) el primer URI falla y el segundo URI tiene éxito, y (3) ambos URI fallan. Este código es lo suficientemente complejo como para probar estos diferentes escenarios usando JUnit, pero para hacer esto, o bien necesito ejecutar servicios web independientes o burlarme de las llamadas API de clientes de Jersey.

+0

¿Qué es exactamente lo que desea probar en este método? ¿Cuáles son los criterios, esa prueba se pasa? – dbf

+0

Bueno, si quieres hacer una prueba unitaria, entonces debes tener los servicios funcionales adecuados. – iDroid

+0

@dbf Actualicé la pregunta con la que quiero probar (1) pasar un URI válido y recuperar una cadena válida y (2) pasar un URI inválido (por alguna razón, inalcanzable o no autorizado) y obtener una excepción espalda. – BennyMcBenBen

Respuesta

12

Intente utilizar Mockito o Easymock para llamadas de servicio burlonas. Debe burlarse solo de estos métodos que realmente se usan, no es necesario burlarse de todos los métodos. Puedes crear un objeto de prueba para la clase WebResource, luego simular aceptar la llamada al método.

En BeforeClass @/@ Antes de la prueba JUnit método de escritura algo así como (ejemplo Mockito)

WebResource res = mock(WebResource.class); 
when(res.accept(something)).thenReturn(thatWhatYouWant); 

Luego, en sus pruebas de que puede utilizar res objeto como si fuera objeto real y la llamada al método simulacro en él. En lugar de devolver el valor, también puedes lanzar excepciones. Mockito es bastante genial.

+1

Esta es la respuesta correcta. Hacer un servicio web completo es gastar esfuerzo en probar el código de Jersey cuando ya sé que funciona. Quiero probar mi código. Terminé refaccionando las llamadas al código de Jersey a otra clase, agregando un setter y burlándome de la nueva clase. Esto funcionó perfectamente y me permitió probar los diferentes escenarios que realmente quería probar. Mi equipo está usando JMock, así que terminé usando eso, pero cualquier marco burlón funcionará. – BennyMcBenBen

+0

Estoy un poco confundido ya que el sitio web de Mockito dice "¡No te burles del tipo que no posees!" ¿Dónde dibujamos una línea en cuanto a qué podemos burlar versus no hacerlo? ¿Hay una mejor manera? –

0

Simplemente implemente un servicio similar para el trabajo y en la configuración de prueba de su unidad, inicie el servicio utilizando HttpServerFactory.

11

Lo que realmente busca es "la forma en que uso el Jersey Client DSL produce una solicitud a la URL correcta con la carga útil correcta y los parámetros de URL". Prueba de esto con Mockito es muy detallado y el código de configuración por lo general terminan buscando algo como esto:

when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication); 
    when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication); 
    when(testAuthentication.request(
      MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder); 
    when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse); 
    when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse()); 

Y esto es básicamente sólo para una única solicitud REST. Es excesivamente detallado, y en lugar de probar el resultado esperado, solo está replicando los pasos que cree que son correctos al usar el DSL de Jersey Client.

En lugar de lo anterior, me gustaría burlar un servicio simple.Para esto, he usado WireMock, que inicia un servidor Jetty y donde puedo resguardar cosas como "esperan una solicitud a esta URL, responden con este mensaje y verifican que la carga útil es esta".

Sé que esto está mejorando en una prueba de integración y es un poco más lento que simplemente usar Mockito pero valoro probar el resultado real y valoro más la legibilidad de las pruebas en este caso.

de configuración para un cliente de prueba WireMock Jersey basada ve algo como esto:

@Test 
public void exactUrlOnly() { 
    stubFor(get(urlEqualTo("/some/thing")) 
      .willReturn(aResponse() 
       .withHeader("Content-Type", "text/plain") 
       .withBody("Hello world!"))); 

    assertThat(testClient.get("/some/thing").statusCode(), is(200)); 
    assertThat(testClient.get("/some/thing/else").statusCode(), is(404)); 
} 
+0

+1 para WireMock: excelente herramienta. En mi caso, Mockito no pudo burlarse de WebResource.Builder (final), resuelto con WireMock – denismo

Cuestiones relacionadas