domingo, 27 de enero de 2008

Data Driven Test (II)

En una de mis ultimos posts había tocado el tema de los JUnit parametrizados, y había presentado una solución simple; ahora, experimentando un poco, me he encontrado con una solución un poco mas sencilla y como en lo personal prefiero las cosas sencillas aquí la presento.

La solución es sencilla, consiste en crear un constructor parametrizado y un método que ejecute la lógica de la prueba. Pongamoslo en código:


public class TestParametrizado {
private int parametro = 0;

public TestParametrizado(int parametro) {
//Es necesario que el nombre del método este en la llamada a super
super("metodoParametrizado");
this.parametro = parametro;
}

public void metodoParametrizado() {
; //Lógica de metodos parametrizados
}
}


Ahora viene la pregunta del millon, no podemos correr este test con los métodos regulares, por la simple y sencilla razón de que JUnit intentara crear una instancia nueva con un constructor sin parametros, en resumen, no funcionará.

Para solucionar este pequeño inconveniente vamos a transformar nuestro TestCase en un test suite.


//Este método debe estar en la misma clase que lo anterior
public static Test suite() {
TestSuite suite = new TestSuite();

suite.addTest(new TestParametrizado(4));
suite.addTest(new TestParametrizado(5));
suite.addTest(new TestParametrizado(7));

return ts;
}

lunes, 21 de enero de 2008

JUnit con Spring

En ocasiones es necesario poder realizar pruebas unitarias sobre algunos componentes que ya hemos configurado previamente en Spring, esto se convierte en algo un poco complicado pues es un hecho que ahora no podemos acceder de manera simple o directa a nuestros beans, dado que la instanciación de los mismos esta en manos de Spring.

Para solucionar este problema podemos hacer uso de los métodos setUp de TestCase y de unas simples instrucciones para poder realizar las pruebas; la idea simplemente es cargar un BeanFactory que tenga la misma configuración que tendría nuestro entorno Web y poder desde este factory obtener los beans.

Una aproximación a este problema podría incluir cargar un Mock del servlet container para cargar todo. Esto presenta sus ventajas pero en lo personal me agradan las soluciones simples.

Para empezar, podemos crear un simple Resource que nos indique donde esta nuestro archivo de beans:


Resource res = new ClassPathResource("applicationContext.xml");


Esto debería cargar el archivo applicationContext.xml desde el classpath. Si el archivo esta dentro de WEB-INF/clases pues la carga se realiza sin problemas, pero si esto no funciona aún queda la solución de usar un FileSystemResource, esto no afectara de manera significativa las pruebas.

A partir de nuestra instancia de recurso podemos crear un BeanFactory que se configure por medio de XML para poder acceder a nuestros beans:


XmlBeanFactory factory = new XmlBeanFactory(res)


Y listo, tenemos una instancia que podemos usar para obtener nuestros beans. En contra de esta solución puedo decir que no puedes conservar todos los scopes de Spring, pero en un UnitTest no deberías tener tantas dependencías.

Ahora, si podemos esto en una clase de TestCase...


public class BasicSpringTestCase extends TestCase {
protected XmlBeanFactory factory = null;

protected void setUp() {
Resource res = new ClassPathResource("applicationContext.xml");
factory = new XmlBeanFactory(res);
}
}

//Aquí ya no necesitamos hacer nada... solamente consumir nuestros beans
public class TestSpring extends BasicSpringTestCase {
public void testSomething() {
Object bean = factory.getBean("id_bean");
}
}

martes, 8 de enero de 2008

Data Driven Test (Update)

Solamente un pequeño comentario, en ocasiones pensamos que las pruebas de record-and-play es una buena solución para crear pocas líneas de código, y en realidad si nos dan bastante libertad, sin embargo, como toda solución, tiene sus peros. En este caso mencionare algunos de ellos:


  • No puedes completar el record de la prueba hasta que se pueda pasar el test.

  • Aun cambios mínimos requieren que se vuelva a grabar el test.

  • Generalmente el test graba la interacción, no los resultados esperados o no lo hace con el detalle deseado.

  • Grabas muchas veces lo mismo (como el Login)



Operaciones muy sencillas pueden ayudarnos a simplificar la mayoría de estos tests, reorganizando la funcionalidad en maneras más prácticas; en este caso vamos a ver una aproximación a los Tests Configurables por medio de TestCase y TestSuites.

Un TestSuite es una clase que agrupa varios TestCase's dentro de uno mismo, permitiendo ejecutarlos como un todo. Por lo menos esa es la funcionalidad regular que se le da. Pero podemos usarlo para parametrizar nuestros TestCase's y asi hacer más flexible y repetible su ejecución. Vamos con un ejemplo:


public class TestParametrizado extends TestCase {
private int value;

public TestParametrizado (int valor) {
this.value = valor;
}

public void testParametrizado() {
int resultado = this.value * 4;
assertEquals(resultado % 4, 0);
}

public void runTest() {
testParametrizado();
}
}

public class TestSuiteSample {
public static TestSuite suite() {
TestSuite ts = new TestSuite();
ts.addTest(new LoginTest());
ts.addTest(new TestParametrizado(3));
ts.addTest(new LoginTest());
ts.addTest(new TestParametrizado(4));
}
}


Con una técnica tan sencilla podemos entonces crear TestCase's mas explicitos, donde estamos repitiendo aquellas cosas que son repetibles, y parametrizando aquello que sea parametrizable.

domingo, 6 de enero de 2008

Selenium Server + JUnit

Selenium no solamente puede utilizarse de la manera que se menciono en el post anterior, sino que puede usarse de manera practicamente automatizada con varios lenguajes de programación, obviamente uno de ellos es Java.

Utilizando Selenium Server podemos desarrollar nuestras pruebas en el lenguaje ya conocido, Java, y podemos observar el comportamiento en el navegador real. Este post explica a groso modo la manera de comenzar con este proceso.

Nota: Para el ejemplo se asume que se utilizara Firefox y por ende, que este se encuentra instalado en la computadora donde se realizaran las pruebas, si desea utilizar IE en lugar de Firefox sustituya la cadena "*firefox" por "*iexplore".

Iniciar Selenium Server




  1. Primeramente es necesario descargar el software Selenium RC del site de Selenium.

  2. Extraer el contenido del archivo descargado

  3. Abrir una consola (cmd o terminal) y moverse al directorio donde se extrajo Selenium RC

  4. Cambiar a la carpeta selenium-server-x.x. Dependiendo el numero de la versión usada

  5. Dentro de esta carpeta teclear java -jar selenium-server.jar. Como resultado debera aparecer la consola del servidor indicando que esta escuchando en el puerto 4444.



Desarrollo de la prueba



El proceso de desarrollo llegará a escribir un simple TestCase que abra la página de Google. El código será parecido al siguiente (JUnit 3.8).


package selenium.test.sample;

import junit.framework.TestCase;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;

public class TestInicial extends TestCase {
private Selenium selenium;

protected void setUp() {
selenium = new DefaultSelenium("localhost", 4444,
"*firefox", "http://www.google.com.mx");;
selenium.start();
}

public void test1() {
selenium.open("http://www.google.com.mx/");
assertNotNull(selenium.getTitle());
}

protected void tearDown() {
selenium.stop();
}
}


Para poder compilar el test es necesario agregar al CLASSPATH actual las librerias que estan dentro de la carpeta selenium-java-client-x.x de la distribución de Selenium RC.

Una vez desarrollado el test procedemos a ejecutarlo, como resultado del mismo deberíamos de ver que se abre un navegador, este carga la página de Google, y se cierra inmediatamente. A manera de ejemplo se ha agregado un pequeño test que nos dice que obtuvimos una página con titulo.

Las posibilidades de prueba van desde enlaces, tablas, etc. Para asegurarse de entender estas capacidades puede leerse la documentación de Selenium que acompaña la distribución de Selenium RC.