java - pruebas a web services
¿Pruebas unitarias de un servicio web JAX-RS? (10)
Actualmente estoy buscando formas de crear pruebas automatizadas para un servicio web JAX-RS (API de Java para servicios web RESTful).
Básicamente necesito una forma de enviar ciertas entradas y verificar que obtengo las respuestas esperadas. Prefiero hacer esto a través de JUnit, pero no estoy seguro de cómo se puede lograr eso.
¿Qué enfoque usas para probar tus servicios web?
Actualización: Como señaló entzik, desacoplando el servicio web de la lógica comercial me permite probar la lógica de negocio. Sin embargo, también quiero probar los códigos de estado HTTP correctos, etc.
Una cosa importante que hacer es probar de forma independiente su lógica comercial
Ciertamente no asumiría que la persona que escribió el código JAX-RS y que está buscando probar la interfaz de alguna manera es, de alguna manera, extraña y inexplicable, ajena a la idea de que él o ella pueda probar unidades en otras partes del programa, incluidas las clases de lógica de negocios. No es útil decir lo obvio y se hizo repetidamente el hecho de que también se deben probar las respuestas.
Tanto Jersey como RESTEasy tienen aplicaciones cliente y en el caso de RESTEasy puede usar las mismas molestias (incluso factorizar la interfaz anotada y usarla en el lado del cliente y del servidor de sus pruebas).
NO DESCANSE lo que este servicio puede hacer por usted; DESCANSE lo que puede hacer por este servicio.
Aunque es demasiado tarde desde la fecha de publicación de la pregunta, pensó que esto podría ser útil para otros que tienen una pregunta similar. Jersey viene con un marco de prueba llamado Jersey Test Framework que le permite probar su servicio web RESTful, incluidos los códigos de estado de la respuesta. Puede usarlo para ejecutar sus pruebas en contenedores livianos como Grizzly, HTTPServer y / o EmbeddedGlassFish. Además, el marco podría usarse para ejecutar sus pruebas en un contenedor web común como GlassFish o Tomcat.
Como dijo James; Hay un marco de prueba incorporado para Jersey. Un simple ejemplo de hello world puede ser así:
pom.xml para la integración de maven. Cuando mvn test
. Los marcos comienzan un contenedor grizzly. Puede usar embarcadero o tomcat a través de dependencias cambiantes.
...
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.16</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
</dependencies>
...
ExampleApp.java
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ExampleApp extends Application {
}
HelloWorld.java
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
public final class HelloWorld {
@GET
@Path("/hello")
@Produces(MediaType.TEXT_PLAIN)
public String sayHelloWorld() {
return "Hello World!";
}
}
HelloWorldTest.java
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.core.Application;
import static org.junit.Assert.assertEquals;
public class HelloWorldTest extends JerseyTest {
@Test
public void testSayHello() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
@Override
protected Application configure() {
return new ResourceConfig(HelloWorld.class);
}
}
Puede verificar this aplicación de muestra.
Eche un vistazo al generador de cliente de reposo Alchemy . Esto puede generar una implementación proxy para su clase de servicio web JAX-RS utilizando el cliente jersey detrás de la escena. Efectivamente, usted llamará sus métodos de servicio web como métodos simples de java de las pruebas de su unidad. Maneja la autenticación http también.
No hay generación de código involucrada si necesita simplemente ejecutar pruebas para que sea conveniente.
Descargo de responsabilidad: soy el autor de esta biblioteca.
Mantenlo simple. Eche un vistazo a https://github.com/valid4j/http-matchers que se pueden importar desde Maven Central.
<dependency>
<groupId>org.valid4j</groupId>
<artifactId>http-matchers</artifactId>
<version>1.0</version>
</dependency>
Ejemplo de uso:
// Statically import the library entry point:
import static org.valid4j.matchers.http.HttpResponseMatchers.*;
// Invoke your web service using plain JAX-RS. E.g:
Client client = ClientBuilder.newClient();
Response response = client.target("http://example.org/hello").request("text/plain").get();
// Verify the response
assertThat(response, hasStatus(Status.OK));
assertThat(response, hasHeader("Content-Encoding", equalTo("gzip")));
assertThat(response, hasEntity(equalTo("content")));
// etc...
Probablemente haya escrito algún código Java que implemente su lógica comercial y luego haya generado el punto final de los servicios web.
Una cosa importante que hacer es probar de forma independiente su lógica comercial. Como es un código Java puro, puedes hacerlo con pruebas regulares de JUnit.
Ahora, dado que la parte de servicios web es solo un punto final, lo que quiere asegurarse es que la plomería generada (stubs, etc) esté sincronizada con su código java. puede hacerlo escribiendo pruebas JUnit que invoquen a los clientes Java del servicio web generado. Esto le permitirá saber cuándo cambia sus firmas java sin actualizar los servicios web.
Si el sistema de compilación genera automáticamente la plomería de servicios web en cada compilación, puede que no sea necesario probar los puntos finales (suponiendo que todo se haya generado correctamente). Depende de tu nivel de paranoia.
Puede probar REST Assured lo que hace que sea muy simple probar los servicios REST y validar la respuesta en Java (usando JUnit o TestNG).
Según tengo entendido, el principal objetivo del autor de este problema es desacoplar la capa JAX RS de la empresa. Y la unidad prueba solo la primera. Aquí hay dos problemas básicos que debemos resolver:
- Ejecutar en prueba un servidor web / de aplicaciones, poner los componentes de JAX RS en él. Y solo ellos.
- Servicios de negocios simulados dentro de los componentes JAX RS / capa REST.
El primero se resuelve con Arquillian. El segundo está perfectamente descrito en arquillican y mock
Este es un ejemplo del código, puede diferir si usa otro servidor de aplicaciones, pero espero que obtenga la idea básica y las ventajas.
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import com.brandmaker.skinning.service.SomeBean;
/**
* Created by alexandr on 31.07.15.
*/
@Path("/entities")
public class RestBean
{
@Inject
SomeBean bean;
@GET
public String getEntiry()
{
return bean.methodToBeMoked();
}
}
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.google.common.collect.Sets;
/**
*/
@ApplicationPath("res")
public class JAXRSConfiguration extends Application
{
@Override
public Set<Class<?>> getClasses()
{
return Sets.newHashSet(RestBean.class);
}
}
public class SomeBean
{
public String methodToBeMoked()
{
return "Original";
}
}
import javax.enterprise.inject.Specializes;
import com.brandmaker.skinning.service.SomeBean;
/**
*/
@Specializes
public class SomeBeanMock extends SomeBean
{
@Override
public String methodToBeMoked()
{
return "Mocked";
}
}
@RunWith(Arquillian.class)
public class RestBeanTest
{
@Deployment
public static WebArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(JAXRSConfiguration.class, RestBean.class, SomeBean.class, SomeBeanMock.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
System.out.println(war.toString(true));
return war;
}
@Test
public void should_create_greeting() {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://127.0.0.1:8181/test/res/entities");
//Building the request i.e a GET request to the RESTful Webservice defined
//by the URI in the WebTarget instance.
Invocation invocation = target.request().buildGet();
//Invoking the request to the RESTful API and capturing the Response.
Response response = invocation.invoke();
//As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
//into the instance of Books by using JAXB.
Assert.assertEquals("Mocked", response.readEntity(String.class));
}
}
Un par de notas:
- La configuración de JAX RS sin web.xml se usa aquí.
- JAX RS Client se usa aquí (sin RESTEasy / Jersey, exponen una API más conveniente)
- Cuando comienza la prueba, el corredor de Arquillian comienza a trabajar. Here puede encontrar cómo configurar las pruebas para Arquillian con el servidor de aplicaciones necesario.
- Dependiendo del servidor de aplicaciones elegido, una url en la prueba diferirá un poco. Se puede usar otro puerto. 8181 es utilizado por Glassfish Embedded en mi ejemplo.
Espero, será de ayuda.
Utilizo HTTPClient de Apache (http://hc.apache.org/) para llamar a Restful Services. La biblioteca HTTP Client le permite realizar fácilmente get, post o cualquier otra operación que necesite. Si su servicio utiliza JAXB para el enlace xml, puede crear un JAXBContext para serializar y deserializar las entradas y salidas de la solicitud HTTP.
Jersey viene con una gran API cliente RESTful que hace que las pruebas de unidades de escritura sean realmente sencillas. Consulte las pruebas unitarias en los ejemplos que se envían con Jersey. Utilizamos este enfoque para probar el soporte de REST en Apache Camel , si está interesado, los casos de prueba están aquí