9.9.11

Cómo utilizar el API de Paypal en Java (III)

4. Poniendo el código en el proyecto

He creado un sencillo proyecto con un único paquete y he puesto en él los dos ficheros de código generados por el wizard de Paypal. Como se puede ver tienen algunos fallitos, pero nada que sea difícil de corregir.

Vamos a empezar añadiendo al código el botón de pago por Paypal (creado por el wizard). Cuando el cliente pulsa este botón, significa que quiere pagar mediante Paypal, así que tendremos que hacer la operación SetExpressCheckout.

Por no complicar el ejemplo, utilizaré el formulario vacío creado por el wizard. He añadido el formulario al servlet EjemploPaypalServlet y he modificado la URL de la etiqueta action del formulario. El código completo se muestra a continuación.




package ejemplopaypal;

import java.io.IOException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class EjemploPaypalServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
HttpSession session = req.getSession(true);
session.setAttribute("Payment_Amount", "30.00");

resp.setContentType("text/html");
resp.getWriter().println("-- Código del formulario aquí --");
}
}



Al pulsar el botón, se ejecutarà el código que invoca la operación de la API que ya generó el wizard (archivo expresscheckout.java), pero hay que modificar este archivo un poco para que funcione.

Además, se ha añadido al servlet una variable de sesión que guarda el total del pedido que facturará Paypal.


5. Operación SetExpressCheckout

El archivo expresschecout.java es un Servet que realiza una operación utilizando los métodos del paypalfunctions.java, en concreto, el método: CallShortcutExpressCheckout (paymentAmount, returnURL, cancelURL);

Lo primero que tenemos que hacer es añadirle la declaración del paquete. En mi caso es esta: package ejemplopaypal;
Una vez añadida esta línea, el código ya no da más errores sintácticos.
Para poder invocar a CallShortcutExpressCheckout necesitamos tres parámetros: la cuantía total de la factura, la URL a la que paypal nos enviará si el cliente confirma el pago y la URL la que nos enviará si surge un error. Los dos últimos parámetros ya los tenemos bien configurados gracias a las URLs que pusimos en el wizard.
La cantidad, se toma de una variable de sesión de tipo String con clave Payment_Amount. Ya vimos en el código de EjemploPaypalServlet como ponerlo.

Para aprender un poco como funciona Paypal, os aconsejo que hagáis una modificación al código para que os muestre todo lo que Paypal responde al invocar al método CallShortcutExpressCheckout . Para eso, podemos modificar el código del archivo expresscheckout.java) añadiendo las siguientes líneas:


// Buscar esta línea
HashMap nvp = ppf.CallShortcutExpressCheckout (paymentAmount, returnURL, cancelURL);

//* -- Añadir
for (Object o: nvp.entrySet()) {
Map.Entry e = (Map.Entry)o;
System.out.println(e.getKey() + ": " + e.getValue());
}

String strAck = nvp.get("ACK").toString();




Nota: Google Application Engine soporta las sesiones de Servlets, pero este soporte no está activdo por defecto. Para que funcione es necesario añadir la etiqueta sessions-enabled con un valor a true

Aún no podemos ejecutar el sistema, ya que paypalfunctions tiene errores que hay que corregir. Eso es justo lo que haremos a continuación.

30.8.11

Cómo utilizar el API de Paypal en Java (II)

2.5. Creando una tienda de prueba

Antes de continuar, vamos a crear una cuenta vendedora para usarla en nuestro ejemplo. Lo primero es ir al sandbox (https://developer.paypal.com/) y hacer login con el usuario y clave que registrado en el paso anterior (ver la primera entrada de este tutorial).

Allí, vamos a l opción API Credentials y creamos una nueva cuenta asegurándonos que es una cuenta de tipo vendedor (Seller). Cuando tengamos el código hecho, comprobaremos que nuestra cuenta compradora ha pagado y nuestra cuenta vendedora ha recibido el dinero. Pero eso será al final del tutorial.

Una vez hecho esto, veremos los datos que necesitamos para acceder a la API. Vamos a copiarlos que los necesitaremos más adelante. Un detalle, comprobad que las cuentas están enabled, si alguna os aparece como disable, pulsad en esa misma palabra (“disabled”) para activarla.


3. Creando el código con el wizard de Paypal

Por suerte, Paypal puede generar el código que necesitamos gracias a su wizard. La URL es: https://www.paypal-labs.com/integrationwizard/

En el wizard, elegimos la opción 1, así crearemos el código necesario para el flujo de Express Checkout (consulta la documentación de desarrolladores de Paypal, ahí viene bien explicado).

En cuanto a lenguaje, elegimos “Java SDK”, como URLs yo usaré: http://localshost:8888/sucess y http://localshost:8888/cancel. Si tu contenedor de Servlets (Tomcat, Jetty, etc.) está configurado para usar una URL distinta, usa dicha URL.
Ahora, copia el código HTML generado y guárdalo.

Copia los dos archivos .java y guárdalos también. Veamos lo que son. El archivo expresscheckout.java es el servlet que ejecuta la primera operación del API SetExpressCheckout y redirige al servidor de Paypal. El archivo paypalfunctions.java es un objeto que contiene métodos para invocar operacons del API de Paypal que vamos a necesitar.

S quieres puedes continuar generando el código para elr estod e los psos. Pero, con lo que ya tenemos, podemos montar la primera operación (SetExpresscheckout) e, incluso, las otras dos operaciones escirbiéndo algo de código por nosotros mismos.

Si quieres puedes continuar generando el código para el resto de los pasos. Pero, con lo que ya tenemos, podemos montar la primera operación e, incluso, las otras dos operaciones escribiendo algo de código por nosotros mismos.

Manos a la obra (en la siguiente entrega).

27.8.11

Cómo utilizar el API de Paypal en Java

El objetivo de este tutorial es crear un sistema Java muy básico que sea capaz de realizar un pago utilizando Paypal. Nuestro sistema se conectará con Paypal, le dirá lo que tiene que cobrar, nos enviará a la página de Paypal y recibirá el resultado de la operación.

Lo que necesitas para seguir este tutorial es el J2EE de Java (cualquier versión vale), ya que en este tutorial usaremos Servlets. Además, necesitarás un servidor capaz de ejecutar los Servlets. Cualquier Tomcat o Jetty debería servir. En mi caso concreto he utilizado Google Application Engine, no por nada en especial sino porque es lo que tengo más a amno ahora.

Empezamos.


1. Un poco de teoría

Lo que vamos a implementar es un pago express, o express checkout, el cuál es uno de los servicios que Paypal ofrece. Para hacer este pago sólo tenemos que hacer tres operaciones con (y una de ella no es obligatoria). Veámoslas:

SetExpressCheckout: Prepara un nuevo pago. La llamaremos justo antes de enviar a un cliente a Paypal. El servidor nos devolverá el token que identifica el pago.

GetExpressCheckout (opcional): Nos permite obtener información sobre el cliente.

DoExpressCheckoutPayment: Concluye y confirma el pago.

Para comunicarnos con Paypal (y hacer las tres operaciones anteriores) tenemos dos opciones, utilizar la API NVP y la API SOAP. NVP son la siglas de Name-Value Pair (par clave-valor) y eso es exactamente en lo que consiste, en construir conjuntos de pares clave valor, con la información que Paypal necesita y mandárselo. En este ejemplo usaremos la API NVP.



2. Creando un usuario de sandbox

Para hacer pruebas necesitamos usuarios de prueba: un usuario que represente la tienda a la que pagamos y usuarios que representen los clientes que hacen el pago. Algunos de ejemplos ya vienen configurados para hacer pagos a una tienda imaginaria, así que vamos a empezar creando un cliente imaginario. Este cliente será el que usemos en Paypal para pagar. Para crear los clientes de pruebas podemos usar esta URL https://developer.paypal.com/

La manera de trabajar es registrarnos en el sandbox para, mediante nuestra cuenta, generar los usuarios de prueba que necesitemos. El proceso no es complejo. La cuenta de correo debe ser auténtica ya que nos mandarán un mensaje para activarla.

Una vez activa, entramos con nuestro correo y contraseña y ya podemos crear nuestra primera test account. En mi caso he creado una cuenta de comprador (buyer) preconfigurada

Ojo que las cuentas se crean con el mismo dominio que la dirección e correo original y variantes aleatorias. Con este método se pueden crear todas las que se quieran.


Ahora sí vámonos de cabeza al código.



Continuará en un par de días.

9.8.11

Nueva página sobre Test-Driven Development y testing: www.portaltdd.org

Actualizo este blog para comentar que estoy participando en la página Portal TDD (www.portaltdd.org)

El objetivo de este portal es publicar referencias a toda la información que aparece en Internet sobre Test-Driven Development y pruebas del softwareen general.
También queremos publicar artículos prácticos y, más adelante, intentar organizar encuentros y promover reuniones para intercambiar experiencias.

Espero veros por allí.

Un saludo.

31.7.08

Seguridad en aplicaciones web y modelos de navegación

Saludos.

Recientemente, por motivos de trabajo, ha caído en mis manos un manual de buenas prácticas de seguridad para el desarrollo de aplicaciones. Después de ojearlo me han pedido unas ideas de cómo poder evaluar que, en el proceso de desarrollo de una aplicación, se está poniendo en práctica todo lo que viene en dicho manual.

Pensando en ello me ha vuelto a quedar patente la importancia, sobre todo en aplicaciones web, de contar con buenos modelos de referencia y, sobre todo, con un buen modelo navegacional. Un modelo navegacional representa (como no puede ser de otra manera) la navegación del sistema. Cuando hablo de navegación no hablo de en qué pantalla estoy y a qué otra pantalla puedo ir. Eso vendrá más adelante y es solo una parte de la navegación.

Los modelos de navegación con los que trabajo (más información en www.iwt2.org), y muchos otros propuestos por empresas e investigadores, son el pegamento de modelos de información, funcionales y de actores / roles, junto con algunos añadidos más.

Un buen modelo navegacional nos dice con precisión cuáles son los actores / roles que interactúan con la aplicación y qué funcionalidad (por ejemplo definida mediante casos de uso) tiene disponible cada uno, qué información y qué campos de dicha información es accesible para cada actor y qué información no lo es (por ejemplo definida mediante prototipos de visualización o diagramas de clases conceptuales), y, por supuesto, a qué otras secciones de la aplicación pueden acceder o no. Todo esto combinado con información sobre validaciones, permisos, etc. incluida en los requisitos funcionales (por ejemplo mediante los mecanismos de precondiciones y postcondicione sutilizados por muchos autores) nos proporcionan abundante información de seguridad
Por supuesto, luego habrá muchas más reglas a tener en cuenta en diseño y en codificación (verificación de parámetros y controles de seguridad en todas las capas, almacenamiento de información encriptada, etc.), pero ya contamos con una buena base de seguridad en nuestros modelos sin necesidad de realizar ninguna inversión en herramientas o técnicas específicas de seguridad.

A divertirse.

16.7.08

Extendiendo PMD con nuevos renderers

PMD es una herramienta de verificación que código Java que permite aplicar un conjunto de reglas (actualmente tiene aproximadamente 240 reglas) y generar un informe con los resultados. En una entrada anterior (http://rincew.blogspot.com/2008/02/escribiendo-reglas-en-pmd.html) conté como escribir una nueva regla. En esta entrada voy a dar unas ideas de cómo desarrollar un nuevo informe de resultados.

Los encargados de procesar los resultados de la verificación se llaman renderers. PMD trae un conjunto de renderers ya construidos para mostrar los resultados como texto, o como HTML, o CSV, o XML. Es útil crear un renderer propio cuando se quiere hacer un procesado adicional, cuando queremos generar un nuevo tipo de resultado, por ejemplo un informa en RTF o añadir el resultado a una BBDD, o cuando queremos ampliar alguno de los renderers ya existentes para incluya información adicional. Hay que recalcar que todas las acciones anteriores pueden hacerse e otra manera, por ejemplo utilizando transformaciones XSLT o las opciones de importación de CSV de la mayoría de sistemas de BBDD.

En PMD, un renderer es una clase que implementa la interfaz Renderer del paquete net.sourceforge.pmd.renderers. Esta interfaz permite que un rederer se comporte como una máquina de estados. Al inicializar el renderer se invoca el método start(), cada vez que se ha aplicado un nuevo conjunto de reglas se invoca al método renderFileReport(Report report) y una vez que se ha acabado el proceso se invoca al método end(). Existen más métodos en esta interfaz, sin embargo no será necesario utilizarlos en este ejemplo.

Como es habitual en muchas librerías y herramientas, PMD ya ofrece una implementación base de esta interfaz en la clase AbstractRenderer (que se mantiene por motivos de compatibilidad con versiones antiguas). A pesar de su nombre, esta clase no es abstracta ni ninguno de sus métodos son abstractos. Tampoco usaremos esta clase como base para los renderers, en su lugar utilizaremos su hija OnTheFlyRenderer, la cuál sí tiene tres métodos abstractos: start, renderFileViolations y end. El funcionamiento de start y end es el mismo que el definido anteriormente, sin embargo, para cada conjunto de reglas, el método invocado será el método renderFileViolations(Iterator violations)


Este método, recibe un iterador con todas las violaciones detectadas para un conjunto de reglas concreto. Una violación es un objetivo de una clase que implementa la interfaz IRuleViolation. A partir de los métodos get de esta interfaz podemos conocer toda la información que PMD maneja del error como el nombre del archivo (método getFilename), la clase y el método de la violación (getClassName y getMethodName), etc.
Además, también podemos obtener toda la información referente a la regla que se ha incumplido con el método getRule. Este método devuelve un objeto que implementa la interfaz Rule y que tiene varios métodos get para conocer el nombre de la regla (getName), su prioridad (getPriority), etc.
A modo de ejemplo, a continuación se muestra un nuevo renderer que también genera una salida de texto plano pero con una información distinta y un orden distinto al renderer de texto que viene de serie en PMD.


import net.sourceforge.pmd.IRuleViolation;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.renderers.OnTheFlyRenderer;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;

public class RendererTexto extends OnTheFlyRenderer {


public void start() throws IOException {

}

public void renderFileViolations(Iterator violations)
throws IOException
{
Writer writer = getWriter();
StringBuffer buf = new StringBuffer();

while (violations.hasNext()) {
IRuleViolation rv = violations.next();
buf.append(PMD.EOL);
buf.append(rv.getFilename());
buf.append(':');
buf.append(Integer.toString(rv.getBeginLine()));
buf.append('\t');
buf.append(rv.getRule().getName());
buf.append(": ");
buf.append(rv.getDescription());

writer.write(buf.toString());
}
}

public void end() throws IOException {
getWriter().write("Ok.");
}

}



Como heredamos de OnTheFlyRenderer solo nos tenemos que preocupar de los tres métodos antes mencionados. En concreto, en el método start no hemos nada. En el método renderFileViolations recorremos cada una de las violaciones mostrando el nombre del fichero y la línea donde ocurre, el nombre de la regla y su descripción. En el método end escribimos la cadena de texto Ok para indicar que el proceso terminó con éxito.
Por último, será necesario indicar a PMD que utilice el nuevo renderer. Para ello es necesario que la clase esté disponible en el classpath del PMD (por ejemplo poniendo el nuevo renderer en una archivo jar y modificando el archivo pmd.bat para que añada dicho jar al classpath en cada ejecución).
Una vez hecho, solo es necesario indicar el nombre de la clase (indicando su paquete) como segundo parámetro. Por ejemplo, si la clase mostrada más arriba está guardada en el paquete pmdext, para utilizar habría que escribir:


PMD c:\src pmdext. RendererTexto basic



Con la línea anterior se verificarían todas las reglas de conjunto de regla basic en todo el código Java dentro de la carpeta src.
En verdad, el mundo de los renderes en PMD es un poco más complejo, ya que no hemos hablado de los writers (aunque se usan en el ejemplo de más arriba). Además, el report no solo nos informa de las violaciones de las reglas sino de los errores que han podido seguir a la hora de procesar un archivo o de las supresiones, es decir, bloques de código marcados para ser ignorados por PMD.
Sin embargo, con estas nociones básicas no es difícil estudiar el código de la clase OnTheFlyRenderer y ver los detalles que no hemos mencionado.
Como comentario final, quiero mencionar que el diseño del mecanismo de renders de PMD no es todo lo bueno y homogéneo que pudiera ser, por suerte es bastante sencillo de usar. Ya se ha anunciado que para la versión 5 se van a hacer cambios de código importantes y se va a romper la compatibilidad hacia atrás, por lo que tengo esperanzas de que mejoren este mecanismo.

21.3.08

Como aplicar inclusiones y extensiones a las plantillas de casos de uso

Saludos.

Muchos de nosotros utilizamos diagramas UML de casos de uso (ver más abajo) y, además, definimos cada caso de uso con plantillas de texto (ver más abajo). Sin embargo, en más de una ocasión ambas representaciones no son consistentes, es decir, hay una información en una de las representaciones que no está en la otra. Esto pasa, por ejemplo, a la hora de definir relaciones de inclusión y extensión. Ambas se definen en los diagramas de casos de uso pero casi nunca se incluyen en las plantillas.
A continuación expongo cómo incluyo yo dichas relaciones en mis plantillas para que sean consistentes con lo que se cuenta en el diagrama de casos de uso.
Como una inclusión debe realizarse siempre, la coloco en la secuencia principal, esto es, en los pasos que se ejecutan salvo algún error o circunstancia anómala. Con esto, además, estoy indicando en qué momento debe realizarse otro caso de uso.
Una excepción, por el contrario, puede realizarse o no dependiendo de una condición (llamada punto de extensión). Si bien los puntos de extensión pueden añadirse a los diagramas de casos de uso en la mayoría de herramientas, yo no suelo hacerlo porque, en cuanto hay más de uno, ya no se sabe qué punto de extensión corresponde a cada extensión. En cambio, añadirlo a la plantilla es muy sencillo. Sólo hay que colocar el punto de extensión y el caso de uso a realizar como un paso de la secuencia alternativa. Si los pasos de la secuencia alternativa están asociados a pasos de la secuencia principal entonces, además, estamos indicando en qué momento concreto debe evaluarse el punto de extensión para decidir si se realiza la extensión o no.
Veamos un ejemplo imaginario. Teneos el caso de uso dar de alta nuevo proyecto, en el cuál, además de introducir la información de cada proyecto, debemos indicar el supervisor del proyecto y el grupo de trabajo encargado. Un proyecto debe tener siempre un encargado, y el comportamiento para seleccionar uno lo definiremos en otro caso de uso. Además, si no encontramos un grupo de trabajo adecuado, podremos crear un nuevo grupo sobre la marcha (mediante otro caso de uso). Con todo esto tenemos tres casos de uso, una inclusión y una extensión. El diagrama correspondiente se muestra a continuación.



Veamos ahora la plantilla del caso de uso dar de alta un nuevo proyecto. Esta plantilla ha sido simplificada al máximo para este ejemplo.



Como se puede observar, las inclusiones y extensiones indicadas en el diagrama de casos de uso también están en la plantilla. Además, se ha indicado información adicional (cuando aparecen las relaciones, cuál es el punto de extensión de la extensión) de manera clara y sencilla sin necesidad de complicar el diagrama de casos de uso.

Feliz semana.

22.2.08

Uso de ant y CPD

La herramienta de detección de copy&paste de PMD (http://pmd.sourceforge.net/) permite detectar fragmentos de código copiados. Esta herramienta, al igual que PMD, también incorpora una tarea ant para poder ser invocada desde dicha herramienta. Sin embargo, no está tan documentada como la tarea ant para CPD. Un ejemplo de su uso se muestra a continuación.



Como cuenta de tokens se ha elegido 50 para que detecte bloques de código repetido de entre 5 o 6 líneas ( si tienen muchos caracteres) hasta 10 u 11 líneas (si tienen pocos caracteres).

(La captura de pantalla está tomada de Microsoft Word, por eso aparecen algunas palabras subralladas).

14.2.08

Escribiendo reglas en PMD

Saludos.

PMD (http://pmd.sourceforge.net/) es un programa para la verificación estática de código Java. PMD contiene bastantes reglas de programación (como no utilizar variables ni muy cortas ni muy largas o no anidar una sentencia if dentro de otra) y su función es buscar qué fragmentos de código incumplen dichas reglas.

A continuación veremos cómo añadir una nueva regla a PMD. Esta herramienta ofrece dos alternativas para las nuevas reglas: implementarlas como código Java o mediante XPath. En este ejemplo usaremos la segunda alternativa. La regla a implementar será: no se permiten genéricos de tipo Object, es decir, no se permiten declaraciones como List[Object] o Set[Object] (uso corchetes en vez de los símbolos de mayor y menor). Puede que esta regla no sea muy útil ya que el declarar genéricos que contienen Objects es tan poco práctico que difícilmente alguien lo va a usar, pero es un buen ejemplo.

Lo primero que tenemos que hacer es ejecutar la herramienta de diseño de reglas que viene con PMD (la propia herramienta viene con un script para ejecutarla). Después, escribimos un fragmento de código que incumpla la regla (como el de la figura 1) y generamos su árbol de sintaxis abstracta (muy similar a un documento XML).

Figura 1.


Ahora, tenemos que escribir una expresión XPath que encuentre sólo aquellos nodos del árbol que incumplen la regla. Para ello, tenemos que buscar aquellas declaraciones de tipo clase o interfaz con un argumento que es un tipo clase object (se puede ver un ejemplo en la figura 1)

Una posible expresión en XPath se muestra a continuación: //ReferenceType/ClassOrInterfaceType/TypeArguments/TypeArgument/ReferenceType/ClassOrInterfaceType[@Image='Object']

Para probarla, la escribimos en el cuadro de la parte superior derecha y la ejecutamos. En el cuadro que está justo debajo vemos las líneas del código Java que incumplen la regla. En la figura 1 se puede observar como la expresión detecta toda las líneas que declaran un genérico de tipo Object.

Para poder utilizar esta regla debemos incluirla en un ruleset, el cuál es un archivo XML que define un conjunto de reglas a verificar. Para no modificar ninguno de los archivos de PMD vamos a crear un nuevo ruleset. La cabecera se muestra a continuación.

[ruleset name="My custom rules" xmlns="http://pmd.sf.net/ruleset/1.0.0" nonamespaceschemalocation="http://pmd.sf.net/ruleset_xml_schema.xsd" schemalocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" xsi="http://www.w3.org/2001/XMLSchema-instance"]

….

[/ruleset]


(De nuevo uso corchetes en vez de los símbolos de mayor y menor).

La propia herramienta de diseño de reglas es capaz de generar el código XML de la regla. Dicho código (figura 2) debe incluirse entre las etiquetas ruleset.

Figura 2.


Ahora, ya es posible utilizar nuestro ruleset como parámetro de PMD para que aplique la regla que hemos definido.

30.10.06

Combinando el modo grabar/reproducir con el modo API de código de Selenium

Saludos.

Selenium (http://www.openqa.org/) es una herramienta open-source estupenda para realizar pruebas de sistema / aceptación de aplicaciones web. Selenium incluye una herramienta que se integra con Firefox y que permite grabar todo lo que hagamos con Firefox, guardarlo en un archivo, y reproducirlo después. Además, Selenium también incluye la posibilidad de escribir nuestras pruebas directamente en Java, C#, Python y Ruby.

Para un proyecto real, estábamos muy interesados en utilizar Selenium y su herramienta para grabar / reproducir pruebas. Sin embargo, queríamos hacer dos cosas que no se pueden hacer con la filosofía de grabar / reproducir: la primera es añadir código adicional que compruebe el estado de la aplicación y el estado de la base de datos y la segunda ejecutar todas las pruebas grabadas automáticamente cada cierto tiempo.

Por suerte el código de una prueba cuando se graba es muy similar al código que habría que escribir en un lenguaje, por ejemplo en Java o CSharp. A continuación incluyo el código de una sencilla prueba

Código 1. Prueba grabada con Firefox.


class NewTest
def test_foo
open "/links_jsp/Default.jsp"
assertTitle "Links"
clickAndWait "//a[contains(@href, 'LinkNew.jsp')]"
assertTitle "Links"
type "name", "Prueba"
type "link_url", "Prueba"
type "description", "URL de prueba"
clickAndWait "//input[@value='Insert']"
assertTitle "Links"
end
end


Código 2. Prueba escrita en Java


import com.thoughtworks.selenium.*;
import junit.framework.*;


public class Selenium_InsertarEnlace extends TestCase {

private Selenium sel;

public void setUp() {
sel = new DefaultSelenium("localhost",
4444, "*firefox", "http:/localhost:8080");
sel.start();
}

public void testInsertarEnlace() {
sel.open("/links_jsp/Default.jsp");
assertEquals("Links", sel.getTitle());
sel.click("//a[contains(@href, 'LinkNew.jsp')]");
sel.waitForPageToLoad("5000");
sel.type("name", "Prueba");
sel.type("link_url", "Prueba");
sel.type("description", "URL de prueba");
sel.click("//input[@value='Insert']");
sel.waitForPageToLoad("5000");
assertEquals("Links", sel.getTitle());
}

public void tearDown() {
sel.stop();
}

public static void main(String[] args) {
junit.textui.TestRunner.run(new TestSuite(Selenium_InsertarEnlace.class));
}
}


Código 3. Prueba escrita en CSharp

using Selenium;
using NUnit.Framework;
namespace MyTests {
[TestFixture]
public class Selenium_InsertarEnlace {
private ISelenium sel;

[SetUp]
public void SetUp() {
sel = new DefaultSelenium("localhost",
4444, "*firefox", "http:/localhost:8080");
sel.Start();
}

[Test]
public void testGoogle() {
sel.Open("/links_jsp/Default.jsp");
Assert.AreEqual("Links", sel.getTitle());
sel.Click("//a[contains(@href, 'LinkNew.jsp')]");
sel.WaitForPageToLoad("5000");
sel.Type("name", "Prueba");
sel.Type("link_url", "Prueba");
sel.Type("description", "URL de prueba");
sel.Click("//input[@value='Insert']");
sel.WaitForPageToLoad("5000");
Assert.AreEqual("Links", sel.getTitle());
}

[TearDown]
public void TearDown() {
sel.stop();
}
}
}



Para ejecutar la prueba en Java, es necesario tener en ejecución el servidor de Selenium ("java -jar selenium-server.jar") y tener en el PATH la ruta a Firefox. Al ejecutar la prueba en Java (necesitamos "selenium-java-client-driver.jar") se abrirá una nueva instancia del Firefox y, en la salida estándar veremos el resultado de la prueba. La prueba en CSharp no la hemos ejecutado, pero debería ser igual de sencillo.

Ahora es posible añadir a la prueba todas las comprobaciones adicionales que queramos como, por ejemplo, conectar con la BBDD para asegurarnos que el enlace está ahí.

Estamos escribiendo un sencillo script para traducir automáticamente el código de una prueba capturada a código Java. Si alguien está interesado no tiene más que escribirme.

25.10.06

Aplicaciones autoadministradas y autoreparadas

Después de asistir a la conferencia de un gurú (o eso dijeron) de la arquitectura de software en un congreso, me llevo la idea de que el desarrollo de aplicaciones que sean capaces de administrase ellas solitas (y de paso repararse) es un buen nicho de mercado.

Esto no es, ni mucho menos, ciencia-ficción. Si no me equivoco la plataforma Java ya incorpora desde hace tiempo interfaces de monitorización de componentes bajo el nombre de JMX.

Para poder hacer esto, dado que la tecnología existe, lo que hay que hacer es plantearlo desde el comienzo del desarrollo de la aplicación e incluir en nuestra aplicación, módulos que monitoricen el funcionamiento de la misma y que tengan la capacidad de tomar las medidas correctivas necesarias. Esto puede venderse muy bien, ya que, como nos comentó el gurú, por cada dólar gastado en adquirir una aplicación (esto incluye el desarrollo a medida), se gastan nueve dólares en su administración y mantenimiento (en euros será menos, seguro). Si podemos desarrollar aplicaciones autoadministradas, podemos reducir el gasto durante toda la vida útil de la aplicación de nuestros clientes 9 veces, lo cuál es bastante interesante.

Además una aplicación que sea capaz de arreglarse a sí misma, es una aplicación que no tiene por qué detenerse nunca, lo cuál es muy beneficioso en ciertos nichos de mercado.

19.10.06

Presentaciones "De casos de uso a casos de prueba" en mi web

Saludos.

He puesto en mi web el 95% de las presentaciones que voy a usar en el seminario "De casos de uso a casos de prueba" que impartiré el martes 24 en el evento SoloRequisitos. La dirección es:

http://www.lsi.us.es/~javierj/cursos.htm

Después del evento publicaré el 100% de las transparencias, aunque el 5% que falta son las menos importantes.

Feliz otoño

18.10.06

Eclipse. Caballo ganador en la investigación

Saludos.

A menudo nos encontramos comparativas entre Eclipse y NetBeans y muchas veces nos da la impresión (al menos a mí) de que ambas plataformas tienen una lucha feroz por imponerse en el mundo de la empresa.
sin embargo en el mundo de la investigación y las universidades no es así. Por lo que he podido ver en un reciente congreso, todo el mundo usa Eclipse y desarrolla sus ideas a partir de Eclipse. En ese sentido, el EMF es una herramienta de uso casi inevitable. Netbeans no aparece por ningún sitio ni se le espera.

¡Dios mío, yo uso Netbeans!. ¿De dónde me puedo descargar Eclipse?.

16.10.06

Evitando el lado oscuro de las pruebas (y II)

Como ya comentamos hace tiempo en este blog, las pruebas de código tipo JUnit tienen un lado oscuro. Si el código cambia, las pruebas pueden quedar inservibles, lo cuál supone un desperdicio de tiempo y recursos.

La solución que propuse fue la de intentar automatizar lo máximo posible la generación de pruebas. Así, si el código cambiaba, simpleente se volvía a ejecutar el programa que generaba un nuevo conjunto de pruebas.

Otra posible solución que se ha comentado en el taller de pruebas es la verificacón estática del código. Es decir, revisar el código para buscar errores antes de ejecutarlo. Según comentaron, las revisiones estáticas de código pueden resolver cerca de un 80% de los errores básicos. Un artículo muy bueno al respecto puede encontrase en (http://in2test.lsi.uniovi.es/pris2006/).

Feliz otoño.

15.9.06

Reglas para escribir buenos casos de uso

Saludos a todos.

Desde principios de verano estoy colaborando con la empresa Icinetic (www.icinetic.com) aplicando algunas de mis ideas sobre pruebas para mejorar su proceso de fabricación de software y también desarrollando nuevos servicios.

Uno de los primeros pasos para poner en marcha un proceso de prueba es tener buenos casos de uso. Cuanto mejor sean los casos de uso, más fácil será fabricar el software y elaborar buenas pruebas. En Icinetic tienen su propio conjunto de reglas para desarrollar buenos casos de uso y, además, me han dado permiso para difundirlas. Estas reglas son:

1. El caso de uso se inicia con la acción de un actor.

2. El caso de uso tiene una precondición y una postcondición

3. Mostrar todas las excepciones posibles, así como los flujos alternativos. Al menos “datos incorrectos” y “error al guardar los datos”

4. Mantener el mismo nivel de abstracción.

5. Rastreabilidad hacia el requisito/s de información y el objetivo/s por el que se ha incluido el caso de uso.

6. Comprobar que las relaciones entre casos de uso (include y extends) sean consecuentes con diagramas de casos de uso.

7. Comprobar que los actores que inician los casos de uso sean consecuentes con los diagramas de caso de uso

8. En las eliminaciones comprobar revisando los requisitos de información si se debería eliminar más elementos en cascada. En tal caso detallarlo en la postcondición.

En general, este conjunto de reglas me parece muy bueno. A continuación incluyo los comentarios que les hice a ellos para que el conjunto de reglas fueran aún mejor.

Completamente de acuerdo con las reglas 1, 4, 6 y 8.
No estoy muy convencido de que un caso de uso deba tener siempre una precondición y una postcondición. Si no identificamos claramente una pre o postcondición vale más la pena no ponerla que forzar la situación.
Por regla general, una precondición expresa el estado que debe tener el sistema para poder ejecutar un caso de uso y una postcondición el estado en el que queda el sistema después de ejecutar un caso de uso. Por ejemplo, no se me ocurre ninguna postcondición para un caso de uso de realizar una búsqueda ya que no cambia nada en el sistema. Poner por poner es para nada.
La regla 5 puede hacerse más genérica. Es buena idea que cualquier requisito sea rastreable, y no solo los requisitos de almacenamiento de información.
La regla 7 me parece un poco ambigua. Cuando, en un diagrama de casos de uso hay más de un actor que participa en un caso de uso, no hay, que yo conozca, ninguna notación para saber cuál es el actor que comienza el caso de uso. Yo les propuse escribir esta regla de una forma más genérica: “comprobar que los actores participantes en un caso de uso son consecuentes con los diagramas de casos de uso”.

Además, les propuse añadir las siguientes reglas, la mayoría sacadas sobre todo del libro “Writting Effective Use Cases” de Cockburn.

9. Si el caso de uso se inicia por la acción de un actor, al final de dicho caso de uso el actor debe obtener un resultado (salvo que el caso de uso sea una inclusión o extensión de otro caso de uso. Entonces, probablemente, no se inicie con a acción de un actor.)
10. Comprobar que el caso de uso sea como un partido de tenis (El actor hace… El sistema hace…) y como un partido de fútbol (se sabe en todo momento qué pasa y quién lo hace)

11. Un caso de uso de 3 pasos o menos o de más de 10 pasos probablemente no sea un buen caso de uso (salvo que el caso de uso sea una inclusión o extensión de otro caso de uso).

12. Todas las acciones similares deben describirse con las mismas frases. Por ejemplo, enunciar todas las inserciones de datos con la frase “El actor X introduce los datos….”. No permitir variantes como “inserta datos”, “añade datos”, “incluye datos”, ni siquiera “introducir datos”, etc. Siempre igual, por muy aburrido que resulte.

Por cierto, la regla 12 es muy útil cuando varias personas distintas escriben casos de uso y también a la hora de utilizar herramientas software de análisis de casos de uso y de generación de pruebas.

Como resumen de todo lo visto: un buen requisito y caso de uso debe tener estas características: completo, correcto, no ambiguo, validado, verificable y rastreable.

a. Un requisito completo es aquel que lo cuenta todo, si hay un limite dice cuál es, si hay algo que hacer dice el qué, etc.

b. Un requisito correcto es aquel que está bien escrito, si faltas de ortografía, ni errores sintácticos y que, además, sigue correctamente las reglas para definir requisitos que se estén usando.

c. Un requisito validado es un requisito que ha sido visto y comprendido por el cliente (y ha dado su visto bueno).

d. Un requisito no ambiguo es aquel requisito que tiene el mismo significado para todo el que lo lea.

e. Un requisito verificable es un requisito que expresa cosas que se pueden probar. Un ejemplo de requisitos no verificables son los que dependen de que una persona haga algo determinado (llevar un paquete, comprobar que los códigos estén correctos, etc.).

f. Un requisito rastreable es un requisito que se sabe de dónde viene y se sabe a dónde va.


P.D.
Autonota. Ahora que retomo la actividad, sería buena idea terminar el curso de Cacuts, a ser posible, utilizando la herramienta Cactus.

6.9.06

Publicaciones en mi web.

Saludos.

He publicado en mi web una página con referencias a todas las propuestas para probar casos de uso que conozco. El enlace es http://www.lsi.us.es/~javierj/approaches.htm

También he publicado un texto dónde se describe brevemente propuestas para especificar pruebas y para implementarlas, tanto para aplicaciones de escritorio como para aplicaciones web. El enlace es http://www.lsi.us.es/~javierj/investigacion_ficheros/EICP.pdf.


Feliz septiembre.
PD: aún está pendiente terminar la serie de pruebas con Cactus.

18.8.06

La desidia del verano

Saludos a todos.

Se supone que el verano, con las vacaciones, sería una época estupendapara escribir un montón de entradas interesantes.

Pues no. La verdad es que, aunque tengo tiempo libre, en verano se apetece escribir nada. Espero volver en septiembre.

Feiz vacaciones a todos.

10.7.06

Un ejemplo de diseño de pruebas con Cactus (II).

Un millón de disculpas por la tardanza, continuamos:

Necesitaremos definir los siguientes elementos para cada caso de prueba: acciones a realizar, valores de prueba, resultado esperado. Por comodidad, vuelvo a poner el comportamiento que el servlet debe tener:


1. El servlet recibe una petición de login con un nombre de usuario y una clave.
1.1. Si el usuario ya se ha registrado, el servlet informa de ello y termina.
1.2. Si el usuario ya lo intentó 3 veces, el servlet informa de ello y termina.
2. En caso contrario, el servlet comprueba el nombre y la clave recibida.
2.1. Si el nombre es válido y la clave coincide, el servlet registra al usuario, informa de ello y termina.
2.2. Si el nombre no es válido o la clave no coincide, el servlet incrementa el número de intentos e informa de ello.


Comencemos.

Las acciones a realizar serán todas las combinaciones posibles, tal y como se muestra a continuación.


c.a) 1 -> 1.1
c.b) 1 -> 1.2
c.c) 1 -> 2 -> 2.1
c.d) 1 -> 2 -> 2.2


La combinación c.a) representa el escenario en el que un usuario solicita el acceso pero ya se había validado. La combinación c.c) representa el escenario en que un usuario solicita el acceso e introduce un nombre y clave correctos, etc.

Además, estás combinaciones pueden repetirse varias veces, tal y como se muestra a continuación:


a) 1 -> 1.1 -> 1 -> 1.1 -> ... (hasta que la sesión expire)
b) 1 -> 1.2 -> 1 -> 1.2 -> ... (hasta que la sesión expire)
c) 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.1
d) 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.1
e) 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.2 -> 1 -> 1.2 -> 1 -> 1.2 -> ... (hasta que la sesión expire)
f) 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.2 -> 1 -> 2 -> 2.1 -> 1 -> 1.1 -> 1 -> 1.1 -> ... (hasta que la sesión expire)


Las repeticiones de combinaciones, en principio, no las tendremos en cuenta, aunque sería interesante probar algunas, por ejemplo la c, la d, la e y la f.

Pasemos ahora a los valores de prueba. En primer lugar identificamos los valores o variables y su dominio:


Nombre de usuario (Cadena de texto)
Clave (Cadena de texto)
Número de intentos (Entero)
Está validado (Booleano)


A continuación dividimos el dominio en distintas categorías. Podemos definir, de manera informal, una categoría como un subconjunto de los valores del dominio para los cuales el sistema siempre presenta el mismo comportamiento. Algunos ejemplos de categorías se muestran a continuación:


Nombre de usuario Correcto / Incorrecto
Clave Correcto / Incorrecto
Número de intentos Menor de 3 / igual a 3 *
Registrado Cierto / Falso

*- Debemos investigar si es posible que el número de intentos sea mayor que 3 o menor que 0.


No todas las categorías pueden tomarse siempre. En general, las categorías posibles estarán restringidas por el camino que estemos probando. Por ejemplo para la secuencia c) (la secuencia de acceso correcto), el número de intentos debe ser menos que tres, el usuario no debe estar registrado y el nombre y la clave deben ser correctos. A continuación se expresan las restricciones de cada una de las combinaciones.


c.a) Registrado = Cierto.
c.b) Registrado = Falso && Numero de intentos = 3
c.c) Registrado = Falso && Numero de intentos < 3 && Nombre = Correcto && Clave = Correcto
c.d) Registrado = Falso && Numero de intentos < 3 && ( Nombre = Incorrecto || Clave = Incorrecto )


A partir de estas restricciones vamos a construir los escenarios de prueba. Un escenario de prueba es una combinación concreta, con un conjunto de valores de prueba concretos que cumplen las restricciones. Cada escenario de prueba es una prueba candidata, es decir, puede convertirse en un caso de prueba. En total, para las cuatro combinaciones del principio hemos identificado 10 escenarios de prueba:


Escenario 1:
Camino a)
Registrado = Cierto.

Escenario 2:
Camino b)
Registrado = Falso
Numero de intentos = 3

Escenario 3:
Camino c)
Registrado = Falso
Numero de intentos = 0

Escenario 4:
Camino c)
Registrado = Falso
Numero de intentos = 2
Nombre = correcto
Clave = correcto

Escenario 5:
Camino d)
Registrado = Falso
Numero de intentos = 0
Nombre = correcto
Clave = incorrecto

Escenario 6:
Camino d)
Registrado = Falso
Numero de intentos = 0
Nombre = incorrecto
Clave = correcto

Escenario 7:
Camino d)
Registrado = Falso
Numero de intentos = 0
Nombre = incorrecto
Clave = incorrecto

Escenario 8:
Camino d)
Registrado = Falso
Numero de intentos = 2
Nombre = correcto
Clave = incorrecto

Escenario 9:
Camino d)
Registrado = Falso
Numero de intentos = 2
Nombre = incorrecto
Clave = correcto

Escenario 10:
Camino d)
Registrado = Falso
Numero de intentos = 2
Nombre = incorrecto
Clave = incorrecto


Aún nos falta decidir cuáles de estos escenarios se implementarán como pruebas con Cactus y definir el resultado esperado de cada escenario. Eso lo veremos en la siguiente entrada, que espero que no tarde tanto como esta.

Feliz verano.

12.6.06

Un ejemplo de diseño de pruebas con Cactus (I).

Saludos y disculpas por la tardanza.

Vamos a ver un sencillo ejemplo donde vamos a diseñar un conjunto de pruebas para un servlet que controla el acceso mediante nombre y clave (el login de toda la vida) y las vamos a implementar con la herramienta Cactus de Apache. Por supuesto, las ideas que veamos pueden aplicarse a otras plataformas de desarrollo web y otras herramientas.
Cactus es una herramienta que nos permite escribir pruebas para código que se ejecute en un servidor, como servlets, JSP, filtros, EJB, etc. Básicamente, una prueba escrita en Cactus se divide en dos partes: la parte cliente y la parte servidor. La parte cliente se ejecuta en nuestra máquina mientras que la parte servidor se ejcuta en el servidor. Más adelante veremos como usarla, ahora vamos a describir el problema y diseñar un conjunto de pruebas.

Vamos a probar el servlet de acceso. Lo primero que necesitamos es el funcionamiento esperado del servlet. Dicho funcionamiento se describe a continuación:

1. El servlet recibe una petición de login con un nombre de usuario y una clave.
1.1. Si el usuario ya se ha registrado, el servlet informa de ello y termina.
1.2. Si el usuario ya lo intentó 3 veces, el servlet informa de ello y termina.
2. En caso contrario, el servlet comprueba el nombre y la clave recibida.
2.1. Si el nombre es válido y la clave coincide, el servlet registra al usuario, informa de ello y termina.
2.2. Si el nombre no es válido o la clave no coincide, el servlet incrementa el número de intentos e informa de ello.

El código del servlet que vamos a probar no lo necesitamos ni para diseñar las pruebas ni para codificarlas. De todas amneras dicho código se muestra a continuación:


import javax.servlet.*;
import javax.servlet.http.*;

public class AccessServlet extends HttpServlet {

private String user ="test";
private String passwd = "test";

protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException
{
HttpSession session;
ServletOutputStream out;
Boolean validUser;
Integer numTries;
String pUser, pPass;

out = resp.getOutputStream();

// 1. Obtengo la sesion.
session = req.getSession();

// 2. Miro si el usuario ya está validado
validUser = (Boolean) session.getAttribute("validUser");
if (validUser != null) {
out.println("

"+"Ya eres un usuario válid");
out.flush();
return;
}

// 3. Comprobamos el número máximo de intentos
numTries = (Integer) session.getAttribute("numTries");
if (numTries == null) {
numTries = new Integer(0);
}

if (numTries.intValue() >= 3) {
out.println("

"+"Demasiados intentos");
out.flush();
return;
}

// 4. Recuperamos los parámetros.
pUser = req.getParameter("f_user");
pPass = req.getParameter("f_password");

// 5. Comprobamos si el nombre y la clave son válidos
if ( pUser.equals(user) && pPass.equals(passwd) ) {
session.setAttribute("validUser", new Boolean(true) );
out.println("

"+"Eres un usuario válido");
out.flush();
return;
}

// 6. Si no, incrementamos en 1 el número de intentos y lo guardamos en la sesión
numTries = new Integer(numTries.intValue()+1);
session.setAttribute("numTries", numTries );
out.println("

"+"Los datos de acceso no son válidos.");
out.flush();

}
}



Por simplicidad, se ha incluido el nombre y la clave válidos en el propio servlet. Si consultáramos con una base de datos, las pruebas que vamos a diseñar a continuación serán exactamente iguales. Sin embargo la arquitectura de pruebas (por ejemplo el setUp() de un caso de prueba) será un poco más complejo.


En la próxima entrada diseñaremos pruebas para probar este servlet y las codificaremos con Cactus.

PD: en el código de ejemplo faltan los println para las etiquetas HTML y BODI.

18.5.06

Extrayendo fragmentos de frases con expresiones regulares

Saludos.

Recientemente, desarrollando unas herramientas de prueba, me he encontrado la necesidad de extraer fragmentos de frases compuestas. Lo que buscaba era poder hacer algo así. Si tengo, por ejemplo, estas dos frases.

1: El niño cogió la pelota con las manos.
2: El niño de azul cogió la pelota grande y morada con las dos manos.

Y quiero aplicar el siguiente patrón.

El $1 cogió $2 con $3

El resultado que quiero es:

1: $1 = "niño", $2 = "la pelota", $3 = "las manos"
2: $1 = "niño de azul", $2 = "la pelota grande y morada", $3 = "las dos manos"


Por suerte encontré una manera rápida y fácil de hacer esto en Java con expresiones regulares y Jakarta RegExp (http://jakarta.apache.org/regexp/index.html). Con esta herramienta escribo el patrón utilizando una expresión regular y encerrando entre paréntesis las expresiones que luego quiero recuperar. Así, el patrón anterior se expresaría de la siguiente forma:

El (.+) cogió (.+) con (.+)

El código para aplicar las frases anteriores al patrón se muestra a continuación.



import org.apache.regexp.*;

public class DemoBlog {

public static void main(String[] args) {

String f1 = "El niño cogió la pelota con las manos.";
String f2 = "El niño de azul cogió la pelota grande y morada con las dos manos.";
String re00 = "El (.+) cogió (.+) con (.+)";

RE re = new RE(re00);
System.out.println("Match: " + re.match(f1) );
System.out.println("Match: " + re.match(f2) );
}
}




El código anterior nos muestra por consola que ambas frases casan con la expresión regular.

Ahora, para extraer la parte de la frase que casa con cada una de las expresiones entre paréntesis del patrón, solo tenemos que llamar a getParen(índice), con índice = 1 para obtener el primer paréntesis e índice = 3 para el último. Por ejemplo:


System.out.println("$1 = " + re.getParen(1) );
System.out.println("$2 = " + re.getParen(2) );
System.out.println("$3 = " + re.getParen(3) );


Además, índice = 0 nos devuelve todo el texto (en este caso la frase completa). Si no queremos saber a priori cuanto paréntesis tenemos, podemos ir llamando a getParen(índice) hasta que este nos devuelva null.


Las clases de expresiones regulares (java.util.regexp) que viene a partir del SE 1.4 (y que comentamos en el post de pruebas con JUnit y expresiones regulares) no permiten hacer lo mismo. O, al menos, yo no he encontrado ninguna manera de hacerlo.

También estuve mirando el proyecto ORO de Jakarta (http://jakarta.apache.org/oro/index.html), por si tuviera algo que me permitiera hacer esto mismo de una manera más potente. Pero en un primer vistazo no he visto nada interesante.