Actualmente estoy buscando formas de crear pruebas automatizadas para un servicio web basado en JAX-RS (API Java para servicios web RESTful).
Básicamente, necesito una forma de enviarle ciertas entradas y verificar que obtengo las respuestas esperadas. Preferiría hacer esto a través de JUnit, pero no estoy seguro de cómo se puede lograr.
¿Qué enfoque utiliza para probar sus servicios web?
Actualización: como señaló entzik, desvincular el servicio web de la lógica empresarial me permite realizar una prueba unitaria de la lógica empresarial. Sin embargo, también quiero probar los códigos de estado HTTP correctos, etc.
Respuestas:
Jersey viene con una excelente API de cliente RESTful que hace que escribir pruebas unitarias sea realmente fácil. Consulte las pruebas unitarias en los ejemplos que se envían con Jersey. Usamos este enfoque para probar el soporte REST en Apache Camel , si está interesado, los casos de prueba están aquí.
fuente
Puede probar REST Assured, lo que hace que sea muy sencillo probar los servicios REST y validar la respuesta en Java (usando JUnit o TestNG).
fuente
Como dijo James; Hay un marco de prueba incorporado para Jersey. Un ejemplo simple de hola mundo puede ser así:
pom.xml para la integración de Maven. Cuando corres
mvn test
. Los marcos comienzan un contenedor grizzly. Puede usar jetty o tomcat cambiando dependencias.... <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 consultar esta aplicación de muestra.
fuente
jersey-hk2
como dependencia porque estaba obteniendo unjava.lang.IllegalStateException: InjectionManagerFactory
error no encontrado (Ver esta pregunta ). De lo contrario, este ejemplo funciona bien.Probablemente haya escrito algún código Java que implemente su lógica empresarial y luego haya generado el punto final de los servicios web para ello.
Una cosa importante que debe hacer es probar de forma independiente su lógica empresarial. Dado que es código java puro, puede hacerlo con pruebas JUnit regulares.
Ahora, dado que la parte de servicios web es solo un punto final, lo que debe 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 de Java sin actualizar las cosas de los servicios web.
Si su sistema de compilación genera automáticamente la plomería de sus servicios web en cada compilación, es posible que no sea necesario probar los puntos finales (suponiendo que todo se haya generado correctamente). Depende de tu nivel de paranoia.
fuente
Aunque es demasiado tarde desde la fecha de publicación de la pregunta, pensé que esto podría ser útil para otras personas 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 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 normal como GlassFish o Tomcat.
fuente
Utilizo HTTPClient de Apache (http://hc.apache.org/) para llamar a Restful Services. La biblioteca del cliente HTTP le permite realizar fácilmente obtener, publicar o cualquier otra operación que necesite. Si su servicio usa JAXB para el enlace xml, puede crear un JAXBContext para serializar y deserializar las entradas y salidas de la solicitud HTTP.
fuente
Eche un vistazo al generador de clientes de descanso de Alchemy . Esto puede generar una implementación de proxy para su clase de servicio web JAX-RS utilizando un cliente jersey detrás de escena. Efectivamente, llamará a sus métodos de servicio web como simples métodos java de sus pruebas unitarias. También maneja la autenticación http.
No hay generación de código involucrada si simplemente necesita ejecutar pruebas, por lo que es conveniente.
Descargo de responsabilidad: soy el autor de esta biblioteca.
fuente
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...
fuente
Ciertamente, no asumiría que la persona que escribió el código JAX-RS y está buscando realizar una prueba unitaria de la interfaz sea de alguna manera, por alguna extraña e inexplicable razón, ajena a la noción de que él o ella puede realizar pruebas unitarias en otras partes del programa, incluidas las clases de lógica empresarial. Difícilmente es útil decir lo obvio y se señaló repetidamente que las respuestas también deben ser probadas.
Tanto Jersey como RESTEasy tienen aplicaciones cliente y, en el caso de RESTEasy, puede usar las mismas anotaciones (incluso descartar 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.
fuente
Según tengo entendido, el propósito principal del autor de este problema es desacoplar la capa JAX RS de la empresarial. Y prueba unitaria solo la primera. Aquí tenemos dos problemas básicos que resolver:
El primero se resuelve con Arquillian. El segundo está perfectamente descrito en arquillican y mock
Aquí hay 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:
Espero que te ayude.
fuente