testing y documentación de servicios rest

95
TESTING Y DOCUMENTACIÓN DE SERVICIOS REST @BORILLO

Upload: ricardo-borillo-domenech

Post on 15-Dec-2014

356 views

Category:

Documents


2 download

DESCRIPTION

Durante esta sesión se abordarán distintos enfoques a la hora de realizar pruebas de nuestros servicios REST.Utilizando la implementación de referencia del estándar Java JAX-RS, se presentarán distintas opciones para poder cargar nuestro entorno, ejecutar nuestras pruebas y gestionar su ejecución en entornos de integración contínua.Por otra parte, se presentarán distintas herramientas que nos permitan elaborar una documentación sencilla y mantenible de nuestras APIs públicas.

TRANSCRIPT

Page 1: Testing y documentación de servicios REST

TESTING Y DOCUMENTACIÓN DE SERVICIOS

REST@BORILLO

Page 2: Testing y documentación de servicios REST

YO { name : 'Ricardo Borillo', company : 'Universitat Jaume I', mail : '[email protected]', social : { twitter : '@borillo', blog : 'xml-utils.com', linkedin : 'linkedin.com/in/borillo' } }

Page 3: Testing y documentación de servicios REST

YO

Page 4: Testing y documentación de servicios REST

ÍNDICE

HTTP y RESTJersey JAX-RSTesting: Objetivos y alternativasMejora de la expresividadDocumentación de los servicios

Page 5: Testing y documentación de servicios REST

HTTP Y REST

Page 6: Testing y documentación de servicios REST

CARACTERÍSTICAS DE REST:

USO DE LOS VERBOS HTTP

Page 7: Testing y documentación de servicios REST

CARACTERÍSTICAS DE REST:

CUALQUIER FORMATO SOBRE HTTP

Page 8: Testing y documentación de servicios REST

CARACTERÍSTICAS DE REST:

ORIENTADO A RECURSOSLista todos los coches o recupera uno:

Añade, modifica o elimina un coche:

GET /carsGET /cars/1234AAW

POST /carsPUT /cars/1234AAWDELETE /cars/1234AAW

Page 9: Testing y documentación de servicios REST

LA GRAN VENTAJA DE REST

APROVECHA AL MÁXIMO LAINSFRASTRUCTURA DE HTTP

Simplicidad, escalabilidad, cacheo, seguridad, ...

Page 10: Testing y documentación de servicios REST

REST != RPCEvitar cosas como:

Utilizar nombres que definen recursos:

/getUsuario/getAllAsuarios/modificaCuentaById

/usuarios/usuarios/1/usuarios/1/facturas

Page 11: Testing y documentación de servicios REST
Page 12: Testing y documentación de servicios REST
Page 13: Testing y documentación de servicios REST
Page 14: Testing y documentación de servicios REST

JERSEY JAX-RS

Page 15: Testing y documentación de servicios REST

¿QUÉ ES?Jersey es la implementación Java de referencia del

estándar JAX-RS para la definición de servicios REST:https://jersey.dev.java.net/

Page 16: Testing y documentación de servicios REST

CONFIGURACIÓN DE UNA APLICACIÓN WEB JERSEYUsando Maven:

<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.17.1</version></dependency>

<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId> <version>1.17.1</version></dependecy>

Page 17: Testing y documentación de servicios REST

¿QUÉ ES?Mapear peticiones HTTP a código Java

@GET / @POST / @PUT / @DELETE@Path("users")public class UsersResource { @GET public List<User> getUsers() { ... }}

GET /users

Page 18: Testing y documentación de servicios REST

¿QUÉ ES?Mapear parámetros de URL a parámetros de entrada a

los métodos

@PathParam / @QueryParam@GET@Path("/users/{userId}")public User getUser( @PathParam("userId") String userId, @QueryParam("debug") @DefaultValue("5") String debug) { }

GET /users/1421?debug=S

Page 19: Testing y documentación de servicios REST

¿QUÉ ES?Declaración del formato de los contenidos recibidos o

emitidos

@Consumes / @Produces@GET@Produces(MediaType.APPLICATION_XML)public List<User> getUsers() { }

@PUT@Consumes(MediaType.APPLICATION_JSON)public void updateUser(User user) { }

Page 20: Testing y documentación de servicios REST

MAPEO DE LA PETICIÓN HTTP:

Page 21: Testing y documentación de servicios REST

MAPEO DE LA RESPUESTA HTTP:

Page 22: Testing y documentación de servicios REST

OTRAS FUNCIONALIDADES DISPONIBLES:HypermediaSeguridad: OAuth, SSL, etcLoggingGestión de excepcionesSoporte para Spring FrameworkAPI de acceso clienteUploads: Jersey MultipartTesting: Jersey Test FrameworkY mucho más ...

Page 23: Testing y documentación de servicios REST
Page 24: Testing y documentación de servicios REST
Page 25: Testing y documentación de servicios REST

Servicios REST: Jersey JAX-RShttps://vimeo.com/53338309

Page 26: Testing y documentación de servicios REST

CÓDIGO DE EJEMPLO:

https://github.com/borillo/template-jersey-spring-jpa

Page 27: Testing y documentación de servicios REST

TESTING:

OBJETIVOS BÁSICOS

Page 28: Testing y documentación de servicios REST

¿QUÉ NOS GUSTARÍA CONSEGUIR?Expresividad y sencillez en las validacionesEntorno integradoArraque automático de los servicios desarrolladosEjecución automática de las pruebasRestitución del entorno

Page 29: Testing y documentación de servicios REST

TESTING:

APROXIMACIÓN INICIAL

Page 30: Testing y documentación de servicios REST
Page 31: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBA través de un navegador web:

Consulta de páginasEnvío de formulariosSubir ficheros al servidor

Page 33: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBDesde línea de comandos

O extrayendo las peticiones de las Chrome Tools

curl -XGET http://www.google.es/

Page 34: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEB

REST SHELLConsola sencilla de utilizar y con completadoCompatible con HATEOAS (soporta discover)Fácil interacción con servicios RESTCarga y guardado de peticiones y respuestasConfiguración del contexto: Cabeceras, auth, etc

Disponible en: GitHub REST-shell

Page 35: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBDefinición del recurso a utilizar:

Acceso a recursos:

http://localhost:8080:> baseUri http://xxxxxxx

Base URI set to 'http://xxxxxxx'

> get resource --params "{ param1 : 'value' }"

> post resource --data "{ param1 : 'value' }"

> post --from data.json

Page 36: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBHATEOAS: discover:

> discover

rel href========================================================people http://localhost:8080/person

> follow people

http://localhost:8080/person:> list

rel href===================================================people.Person http://localhost:8080/person/1people.search http://localhost:8080/person/search

Page 37: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBHATEOAS: get

http://localhost:8080/person:> get 1> GET http://localhost:8080/person/1

< 200 OK< ETag: "2"< Content-Type: application/json<{ "links" : [ { "rel" : "self", "href" : "http://localhost:8080/person/1" }], "name" : "John Doe"}

Page 38: Testing y documentación de servicios REST

HTTP: ACCEDIENDO A CONTENIDOS EN LA WEBDesde algún lenguaje de programación como Java

O con el API cliente de Jersey JAX-RS:

DefaultHttpClient client = new DefaultHttpClient();client.execute(new HttpGet("http://www.uji.es/"));

Client client = Client.create();WebResource resource = client.resource("http://www.uji.es/");ClientResponse response = resource.accept("text/html"). get(ClientResponse.class);if (response.getStatus() == 200) { System.out.println(response.getEntity(String.class));}

Page 39: Testing y documentación de servicios REST

TESTING:

HERRAMIENTAS DEAUTOMATIZACIÓN

Page 40: Testing y documentación de servicios REST
Page 41: Testing y documentación de servicios REST
Page 42: Testing y documentación de servicios REST
Page 43: Testing y documentación de servicios REST

SOAPUI

CREACIÓN DEL PROYECTO

Page 44: Testing y documentación de servicios REST

SOAPUI

EJECUCIÓN DEL SERVICIO

Page 45: Testing y documentación de servicios REST

SOAPUI

CREACIÓN DEL TESTCASE

Page 46: Testing y documentación de servicios REST

SOAPUI

EJECUCIÓN DEL TEST

Page 47: Testing y documentación de servicios REST

SOAPUI

AÑADIR UNA ASERCIÓN

Page 48: Testing y documentación de servicios REST

SOAPUI

VALOR EXPECTED DE LA ASERCIÓN

Page 49: Testing y documentación de servicios REST

SOAPUI

INFORME DE EJECUCIÓN DE LA SUITE

Page 50: Testing y documentación de servicios REST

SOAPUI

INFORME DE EJECUCIÓN DE LA SUITE

Page 51: Testing y documentación de servicios REST
Page 52: Testing y documentación de servicios REST

TESTING:

JERSEY TESTFRAMEWORK

Page 53: Testing y documentación de servicios REST
Page 54: Testing y documentación de servicios REST

DEPENDENCIAS EXTRA NECESARIASAñadir al pom.xml las siguientes dependencias:

<dependency> <groupId>com.sun.jersey.jersey-test-framework</groupId> <artifactId>jersey-test-framework-core</artifactId> <version>1.17.1</version></dependency>

<dependency> <groupId>com.sun.jersey.jersey-test-framework</groupId> <artifactId>jersey-test-framework-grizzly</artifactId> <version>1.17.1</version></dependency>

Page 55: Testing y documentación de servicios REST

DEFINICIÓN DE UN TESTCódigo necesario para arrancar el contenedor Java:public class UsersResourceTest extends JerseyTest { private WebResource resource;

public UsersResourceTest() { super(new WebAppDescriptor.Builder("com.decharlas.services") .contextParam("webAppRootKey", "jersey-maven.root") .servletClass(ServletContainer.class).build()); this.resource = resource(); }

@Override protected TestContainerFactory getTestContainerFactory() { return new GrizzlyWebTestContainerFactory(); }}

Page 56: Testing y documentación de servicios REST

DEFINICIÓN DE UN TESTDefinición de los tests:

public class UsersResourceTest extends JerseyTest {

// Métodos de definición de la slide anterior

@Test public void deleteUser() throws Exception { ClientResponse response = resource.path("users/1") .accept("application/json") .delete(ClientResponse.class);

Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus()); }}

Page 57: Testing y documentación de servicios REST

CÓDIGO DE EJEMPLO:

https://github.com/borillo/template-jersey-spring-jpa

Page 58: Testing y documentación de servicios REST

MEJORANDO LAEXPRESIVIDAD DENUESTROS TESTS

Page 59: Testing y documentación de servicios REST

OBJETIVOSLas aserciones en jUnit no resultan nada semánticas:

Vamos a ver como mejorarlas y así conseguir:

Aserciones más fáciles de leerMenos duplicación de código en las pruebasMejora de la semánticaFacilidad de comprobación de los resultados

Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());

Page 60: Testing y documentación de servicios REST

MEJORANDO LA EXPRESIVIDAD DENUESTROS TESTS:

HAMCREST

Page 61: Testing y documentación de servicios REST

MEJORAR LOS TESTS CON HAMCRESTMatchers para asserts sobre nuestros servicios

public class OkResponseMatcher extends TypeSafeMatcher<ClientResponse> { @Override public boolean matchesSafely(ClientResponse response) { return (response != null && response.getStatus() == 200); }

public void describeTo(Description description) { description.appendText("not a HTTP 200 response"); }

@Factory public static <T> Matcher<ClientResponse> ok() { return new OkResponseMatcher(); }}

Page 62: Testing y documentación de servicios REST

MEJORAR LOS TESTS CON HAMCRESTUso del anterior matcher "OkResponseMatcher"@Testpublic void test() { ClientResponse response = resource.path("users/1").get(ClientResponse.class);

...

assertThat(response, is(ok()));}

Page 63: Testing y documentación de servicios REST

MEJORANDO LA EXPRESIVIDAD DENUESTROS TESTS:

REST-ASSURED

Page 64: Testing y documentación de servicios REST

DEFINICIÓN

Testing and validating REST services in Java is harderthan in dynamic languages such as Ruby and Groovy.

REST Assured brings the simplicity of using theselanguages into the Java domain.

Page 65: Testing y documentación de servicios REST

DEPENDENCIAS EXTRA NECESARIASAñadir al pom.xml las siguientes dependencias:

<dependency> <groupId>com.jayway.restassured</groupId> <artifactId>rest-assured</artifactId> <version>1.8.0</version> <scope>test<scope></dependency>

Page 66: Testing y documentación de servicios REST

CARACTERÍSTICAS PRINCIPALES:Integración HTTP total: Cookies, auth, headers, ...Expresivo DSL para realizar las comprobacionesJsonPath y XmlPath para validar informaciónMatchers Hamcrest para las validacionesCustom parsers por content typeDispone de un StubServerLoggingMucho más!! Consulta la doc oficial :)

Page 67: Testing y documentación de servicios REST

TEST: EL USERID DEBE SER 5 { "User": { "userId": 5, "friends": [{ "userId": 23, "refs": [2, 45, 34, 23, 3, 5] }, { "userId": 54, "refs": [52, 3, 12, 11, 18, 22] }] }}

given().expect().body("User.userId", equalTo(5)). when().get("/users");

Page 68: Testing y documentación de servicios REST

TEST: 23 Y 54 DEBEN ESTAR ENTRE LOS AMIGOS { "User": { "userId": 5, "friends": [{ "userId": 23, "refs": [2, 45, 34, 23, 3, 5] }, { "userId": 54, "refs": [52, 3, 12, 11, 18, 22] }] }}

expect().body("User.friends.userId", hasItems(23, 54)). when().get("/users");;

Page 69: Testing y documentación de servicios REST

TEST: EL SALUDO DEBE SER PARA RICARDO<greeting> <firstName>Ricardo</firstName> <lastName>Borillo</lastName></greeting>

expect().body(hasXPath("//firstName", containsString("Ricardo"))). when().post("/greets");

expect().body(hasXPath("//firstName[text()='Ricardo']")). when().post("/greets");

Page 70: Testing y documentación de servicios REST

INTEGRACIÓN CON JERSEYJersey Test Framework: Arranque servicios REST conGrizzlyConfiguramos REST-assured para conectar a estosserviciosRestAssured.baseURI = "http://localhost";RestAssured.port = this.resource.getURI().getPort();RestAssured.basePath = "/appbasepath";RestAssured.authentication = basic("username","password");

Page 71: Testing y documentación de servicios REST

CÓDIGO DE EJEMPLO:

https://github.com/borillo/template-rest-assured

Page 72: Testing y documentación de servicios REST

DOCUMENTACIÓN DE SERVICIOS REST:

SWAGGER

Page 73: Testing y documentación de servicios REST
Page 74: Testing y documentación de servicios REST

¿QUÉ ES SWAGGER?Swagger is a specification and complete framework

implementation for describing, producing, consuming,and visualizing RESTful web services.

The overarching goal of Swagger is to enable client anddocumentation systems to update at the same pace as the

server. With Swagger, deploying managing, and usingpowerful APIs has never been easier.

Page 75: Testing y documentación de servicios REST

SWAGGER-UI: EL INTERFAZ DE SWAGGERConjunto de ficheros HTML/CSS/JavaScript sinninguna dependencia adicionalDocumentación atractiva y dinámicaPermite la interacción con los servicios RESTSólo es necesario que nuestros servicios REST sean"swagger-compliant"

Page 77: Testing y documentación de servicios REST

SWAGGER-UI: APIS REST "SWAGGER COMPLIANT"Los servicios REST deben exportar su descripción{ apiVersion: "0.2", swaggerVersion: "1.1", basePath: "http://petstore.swagger.wordnik.com/api", apis: [ { path: "/pet.{format}", description: "Operations about pets" }, { path: "/user.{format}", description: "Operations about user" } ]}

Page 78: Testing y documentación de servicios REST

SWAGGER-UI: POSIBILIDADES DE INTEGRACIÓNDisponibles integraciones para múltiples lenguajes yframeworks:

Java/Scala JAX-RSNodeJSGrailsSymfony 2Muchos más ...

Page 79: Testing y documentación de servicios REST

SWAGGER-UI: GENERACIÓN DEL CLIENTE HTMLDescargamos el código del proyecto:

Inicializamos dependencias y construimos:

En el directorio dist tenemos el UI listo para copiar adonde queramos

git clone https://github.com/wordnik/swagger-ui.git

npm installnpm run-script build

Page 80: Testing y documentación de servicios REST

SWAGGER:

INTEGRACIÓN CONJERSEY JAX-RS

Page 81: Testing y documentación de servicios REST

DEPENDENCIAS EXTRA NECESARIASAñadir al pom.xml las siguientes dependencias:

<dependency> <groupId>com.wordnik</groupId> <artifactId>swagger-jaxrs_2.9.1</artifactId> <version>1.2.1</version></dependency>

Page 82: Testing y documentación de servicios REST

CARGA DEL PROVIDER DE SWAGGER EN JERSEYModificar la definición de Jersey en el web.xml:

<servlet> <servlet-name>jersey</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <init-param> <param-name> com.sun.jersey.config.property.packages </param-name> <param-value> com.your.project; com.wordnik.swagger.jaxrs.listing </param-value> </init-param> ...</servlet>

Page 83: Testing y documentación de servicios REST

PARÁMETROS BÁSICOS DE SWAGGERModificar la definición de Jersey en el web.xml:

<servlet> ... <init-param> <param-name>swagger.api.basepath</param-name> <param-value>http://localhost:8080</param-value> </init-param> <init-param> <param-name>api.version</param-name> <param-value>1.0</param-value> </init-param> ...</servlet>

Page 84: Testing y documentación de servicios REST

ANOTACIONES EN LOS SERVICIOS RESTAnotaciones Swagger en nuestro servicios Jersey:

@Path("/pet.json")@Api(value = "/pet", description = "Operations about pets")@Produces({"application/json"})public class PetResource { @GET @Path("/{petId}") @ApiOperation(value="Find pet", notes="Extra notes", responseClass="com.model.Pet") @ApiErrors(value={@ApiError(code=400, reason="Invalid ID supplied"), @ApiError(code=404, reason="Pet not found")}) public Response getPetById ( @ApiParam(value="Pet ID", required=true) @PathParam("petId") String petId) throws NotFoundException { // your resource logic } ...}

Page 85: Testing y documentación de servicios REST

DOCUMENTACIÓN GENERADAAccedemos al índice de servicios documentados:

curl -XGET http://localhost:8080/api-docs.json

{ apiVersion: "1.0", swaggerVersion: "1.0", basePath: "http://localhost:8080", apis: [ { path: "/api-docs.{format}/pet", description: "Operations about pets" } ]}

Page 86: Testing y documentación de servicios REST

DOCUMENTACIÓN GENERADAY luego a la descripción de un servicio:

curl -XGET http://localhost:8080/api-docs.json/pet

{ apiVersion: "1.0", swaggerVersion: "1.0", basePath: "http://localhost:8080", resourcePath: "/pet", apis: [ { path: "/pet.{format}/{petId}", description: "Operations about pets", operations: [ { parameters: [ { name: "petId", ...

Page 87: Testing y documentación de servicios REST

CÓDIGO DE EJEMPLO:

https://github.com/borillo/template-jersey-swagger

Page 88: Testing y documentación de servicios REST

SWAGGER:

INTEGRACIÓN CONNODEJS & EXPRESS

Page 89: Testing y documentación de servicios REST

CONFIGURACIÓN DE SWAGGER-UICopiamos swagger-ui al proyecto y lo inicializamos:var docs_handler = express.static(__dirname + '/swagger-ui/');

app.get(/̂\/docs(\/.*)?$/, function(req, res, next) { if (req.url === '/docs') { res.writeHead(302, { 'Location' : req.url + '/' }); res.end(); return; }

req.url = req.url.substr('/docs'.length); return docs_handler(req, res, next);});

Page 90: Testing y documentación de servicios REST

DESCRIPCIÓN DE LOS MODELOS DE LA APLICACIÓNFichero models.js:

exports.models = { "User": { "id": "User", "properties": { "id": { "type":"long" }, "name": { "type":"string" } } }};

Page 91: Testing y documentación de servicios REST

DESCRIPCIÓN DE LOS RECURSOS RESTexports.getUserById = { 'spec': { "description" : "users", "path": "/users.{format}/{userId}", "notes": "Returns an user based on ID", "summary": "Find user by ID", "method": "GET", "params": [param.path("userId", "ID of the fetched user", "string")], "responseClass": "User", "errorResponses": [ swaggerErrors.invalid('id'), swaggerErrors.notFound('user') ], "nickname": "getUserById" }, 'action': function (req,res) { // procesamiento }};

Page 92: Testing y documentación de servicios REST

CONFIGURAMOS LOS PARÁMETROS DE SWAGGERModelos, recursos, punto de acceso y versión:

var swagger = require("./swagger.js"), resources = require("./resources.js"), models = require("./models.js");

var app = express();app.use(express.bodyParser());

swagger.setAppHandler(app);swagger.addModels(models).addGet(resources.getUserById);swagger.configure("http://localhost:8002", "0.1");

Page 93: Testing y documentación de servicios REST

CÓDIGO DE EJEMPLO:

https://github.com/borillo/template-nodejs-swagger

Page 94: Testing y documentación de servicios REST

¿PREGUNTAS?

Page 95: Testing y documentación de servicios REST