A estas alturas de la película nadie cuestiona la necesidad de realizar pruebas unitarias en todo desarrollo de software. Y cuando se habla de pruebas unitarias se entiende también que deben ser ser automatizables para poder ejecutarlas de manera desatendida (lo normal es que sea por las noches) tal como dice por ejemplo la metodología de la IntegraciónContinua.

Efectivamente, nadie cuestiona su necesidad, pero sin embargo ¿qué pasa en el día a día del desarrollo? que en muchas ocasiones estos test unitarios no se hacen. En muchas ocasiones, no se hacen porque se tiene la idea de que retrasaría el trabajo al tener que desarrollar más software.

Cada vez hacemos software más complejo, sobre todo con una arquitectura orientada a servicios (SOA). Desde que el usuario le da al botón de “aceptar” en la pantalla hasta que aparecen los datos de respuesta, esta petición viaja por un buen número de servidores y aplicaciones, capas y subcapas de software, módulos, librerías de terceros, bases de datos, etc. etc. ¿que pasa cuando algo falla y no tenemos pruebas automatizadas?:

  1. No sabremos en que sitio falla
  2. Tendremos que arrancar toda la aplicación (o varias) para poder reproducir el error. Incluso tendremos que desplegarla en un entorno controlado para poder ver que está fallando.
  3. Si localizamos el error y lo arreglamos, no podremos hacer pruebas de regresión para asegurarnos de que el nuevo cambio no ha estropeado algo que funcionaba antes.

La creación de test unitarios, no es un capricho ni un añadido superfluo al proyecto, forma parte del propio de desarrollo, de la misma manera que un bucle for en nuestro código.

Un nuevo software que probar

Los sevicios web, ya sean SOAP o REST, está explotando en las empresas y están proliferando por doquier. No podemos dejarlos fuera de nuestras pruebas automatizadas. Debemos tener un mecanismo para poder probar la invocación a estos servicios y saber si están caídos o si no funcionan correctamente.

Para facilitar las pruebas de servicios y ahorrar tiempo y complejidad, he preparado una sencilla utilidad que nos permite invocar un servicio SOAP y buscar en el mensaje de resupuesta una cadena de texto que nos diga si la ejecución ha sido correcta.

Como mejor se ve esto es con un ejemplo, así que usaré para ello un servicio muy sencillo que implementa una suma de dos números. El objetivo sería hacer un test que compruebe que la suma se hace correctamente.

Mensaje de entrada y salida de nuestro servicio de ejemplo obtenido con SOAPUI

Para implementar la prueba unitaria en Java seguiremos los siguientes pasos:

  1. obtener el WSDL del servicio. El WSDL es el fichero que describe el interfaz del servicio (parámetros de entrada/salida) y la URL o endpoint del servicio.
  2. Construir un mensaje SOAP suele ser bastante complejo así que usaremos la herramienta gratuita SOAPUIpara construirlo.
  3. Ejecutamos SOAPUI con el mensaje de entrada e invocamos al servicio. Con esto obtendremos el mensaje de vuelta. En esta respuesta seleccionaremos una parte del mismo que pruebe que el mensaje ha sido correcto
  4. Crear un Junit y configurar la invocación al servicio con el SOAP de entrada del punto anterior. Poner un assert que compruebe el resultado correcto.

Para invocar al servicio web es necesario enviar una petición HTTP de tipo POST. Para ello utilizaré un método de una clase de utilidad que recibe como parámetros el endpoint del servicio y el mensaje de entrada. Devolverá un objeto con la respuesta: el código HTTP retornado y el mensaje de salida.

La clase de utilidad es la siguiente:

public class HttpUtil {

            public InvokePostResponse invokeWS(String endpoint, String message) throws Exception {

                        URL url;

                        HttpURLConnection connection = null;

                        InvokePostResponse ipr = new InvokePostResponse();

                        try {

                                   // crea el objeto URL con el endpoint del servicio

                                   url = new URL(endpoint);

                                   // abre la conexión

                                   connection = (HttpURLConnection) url.openConnection();

                                   //Selecciona el método POST.

                                   //Es el método que hay que usar para invocar a un servicio web

                                   connection.setRequestMethod(“POST”);

                                   //configuración de la conexión HTTP

                                   connection.setUseCaches(false);

                                   connection.setDoInput(true);

                                   connection.setDoOutput(true);

                                   //según el estándar SOAP hay que enviar un cabecera HTTP con SOAPAction         

                                   connection.setRequestProperty(“SOAPAction”, “”);

                                   // Enviar la petición mediante un OuputStream

                                   DataOutputStream output = new DataOutputStream(connection.getOutputStream());

                                   output.writeBytes(message);

                                   //vacía el buffer de salida

                                   output.flush();

                                   //cierra el flujo de salida

                                   output.close();

                                   //obtiene el código de respuesta de la petición HTTP

                                   ipr.setHttpCode(connection.getResponseCode());

                                   // Recoge la respuesta del servicio mediante un InputStream

                                   InputStream input;

                                   // si el código es igual o menor de 400 es OK y se coge el input normal

                                   // si es mayor de 400 es que ha habido un error y se coge el input de error

                                   if (connection.getResponseCode() <= 400) {

                                               input = connection.getInputStream();

                                   } else {

                                               input = connection.getErrorStream();

                                   }

                                   //se lee el flujo de entrada línea a línea

                                   BufferedReader rd = new BufferedReader(new InputStreamReader(input));

                                   String line;

                                   StringBuffer response = new StringBuffer();

                                   while ((line = rd.readLine()) != null) {

                                               response.append(line);

                                               response.append(‘\r’);

                                   }

                                   //se cierra elflujo de entrada

                                   rd.close();

                                   //se guarda el mensaje de respuesta en el objeto respuesta

                                   ipr.setMessage(response.toString());

                        } catch (Exception e) {

                                   throw e;

                        } finally {

                                   //se cierra la conexión en un bloque finally para asegurarnos de

                                   //se sierra en cualquier caso

                                   if (connection != null) {

                                               connection.disconnect();

                                   }

                        }

                        return ipr;

            }

}

Clase Test

Por último, sólo nos queda implementar la clase de Test. Usaré JUnit ya que es un framework ampliamente usado e integrado con todas las herramientas de desarrollo. Para implemetar el test necesitaremos:

  1. El endpoint del servicio. Se obtiene del WSDL.
  2. El mensaje de entrada. Se obtiene de la herramienta SOAPUI tal como se ve en la captura de pantalla
  3. El string en el mensaje de vuelta que quiero comprobar y que valida la ejecución del servicio. En este caso como invoco al servicio de suma con los parámetros 2+3, buscaré en la salida el texto <sumaReturn>5.0</sumaReturn>

La complejidad del test se esconde como veis en el método invokeWS al que se le pasa la URL

del endpoint (la URL desde la que responde el servicio), y un string con el mensaje de entrada

(obtenido del SOAPUI)

Obtenemos la respuesta, comprobamos que el código http de respuesta sea 200 y buscamos

un substring en el string de respuesta con la ayuda del método indexOf. En este caso, como

hemos invocado con los valores 2+3 buscaremos “<sumaReturn>5.0</sumaReturn>”

 

@Test

            public void test() {

                        System.out.println(“invocando…”);

                        StringBuffer sb = new StringBuffer();

                                              

                        sb.append(“<soapenv:Envelope xmlns:soapenv=\”http://schemas.xmlsoap.org/soap/envelope/\” “);

                        sb.append(“xmlns:cal=\”http://calculadora.xatacaon\”>”);

                        sb.append(“<soapenv:Header/>”);

                        sb.append(“<soapenv:Body>”);

                        sb.append(“<cal:suma>”);

                        sb.append(“<cal:a>2</cal:a>”);

                        sb.append(“<cal:b>3</cal:b>”);

                        sb.append(“</cal:suma>”);

                        sb.append(“</soapenv:Body>”);

                        sb.append(“</soapenv:Envelope>”);                          

                       

                        HttpUtil h = new HttpUtil();

                       

                        InvokePostResponse response = null;

                        try {

                                   response = h.invokeWS(“http://localhost:8080/CalculadoraWeb/services/Calculadora&#8221;,

                                                           sb.toString());

                        } catch (Exception e) {

                                   Assert.fail(e.toString());

                        }

                       

                        Assert.assertNotNull(“respuesta nula”, response);

                        Assert.assertNotNull(“mensaje de respuesta nulo”, response.getMessage());

                        System.out.println(response.getMessage());

                        Assert.assertTrue(“no devuelve el resultado esperado”, response.getMessage().indexOf(“<sumaReturn>5.0</sumaReturn>”) != -1);  

            }

En un par de minutos tendremos un caso de test que podremos ejecutar de manera automatizada tantas veces como queramos.

Comparte esta entrada:
Share

Anuncios