Escribir el primer Test
Ahora procederás a escribir tu tests, para la aplicación de listín telefónico. Como vas a testear primero, escribe los tests antes de escribir el código que implementa la funcionalidad. De esta forma, puedes estar más seguro de que tus test funcionan y de que la funcionalidad que vas a probar también funciona. Para poder testear, necesitas tener una idea básica de como funcionará tu aplicación. La aplicación del listín telefónico tendrá dos páginas:
- Una página que muestre la lista de contactos con las propiedades básicas de cada contacto (Esta página también te da la opción elegir un contacto para editarlo o elegir contactos para borrarlos).
- Una página que te permite introducir o editar los detalles de un contacto.
Escribe el test para la página que muestra la lista de contactos. El test debería hacer un par de cosas:
- Verificar que la página "mostrar contactos" existe y devuelve algún contenido.
- Verificar que la página "mostrar contactos" muestra una lista de contactos o un mensaje diciendo que no hay contactos.
Ve al directorio ~/projects/phonelist/src/test/com/abcinc/phonelist/test y crea un fichero llamado ShowListTest.java. Inicialmente la clase ShowListTest se debería parecer a esta:
package com.abcinc.phonelist.test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class ShowListTest extends TestCase {
public static void main(String args[]) {
junit.textui.TestRunner.run(suite());
}
public static TestSuite suite() {
return new TestSuite(ShowListTest.class);
}
public ShowListTest(String s) {
super(s);
}
}
La clase contiene dos métodos y un constructor. El método estático main te permite ejecutar la clase desde la línea de comandos o desde un target de Ant <java>, que necesitaremos crear para poder realizar el testeo desde dentro de un target de Ant. El método estático suite ejemplariza un objeto TestSuite, que se pasa al método estático run de la clase TestRunner. Puedes ejemplarizar un objeto TestSuite con una subclase de TestCase o sin ella. Si le pasas un ejemplar de una subclase de TestCase, el constructor de TestSuite escaneará la clase buscando métodos cuyos nombres empiecen por test y que no acepten argumentos. El objeto TestSuite ejecutará automáticamente todos esos métodos de la subclase de TestCase.
Ahora añade el test. Sitúa el siguiente método después del constructor ShowListTest:
public void testShowList() throws Exception {
WebConversation webConversation = new WebConversation();
String url = protocol + "://" + hostname + ":" + port + path;
WebRequest webRequest = new GetMethodWebRequest(url);
WebResponse webResponse = webConversation.getResponse(webRequest);
assertTrue("No content in phone list page", webResponse.getText().length() > 0);
WebTable webTable = webResponse.getTableStartingWith("Phone List");
assertNotNull("Phone List HTML table not found", webTable);
assertTrue("Phone List table has less than 4 rows", webTable.getRowCount() >= 4);
}
El método testShowList realiza las siguientes acciones:
- Envía una petición GET de HTTP al servidor que hay en la localización especificada por un objeto String llamado url.
- Obtiene la respuesta HTTP y la almacena en una variable.
- Verifica que la respuesta contiene más de cero bytes de datos.
- Verifica que la respuesta contiene una tabla HTML que tiene "Phone List" como su primer texto no blanco
- Verifica que la tabla HTML que empieza con "Phone List" tiene al menos tres filas de datos.
Además del código para el método testShowList, también necesitas añadir algunas sentencias import para que se reconozcan las clases de HttpUnit que usas en testShowList. Añade el siguiente código debajo de las dos líneas import junit:
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.TableCell;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;
Observa también que el método testShowList que acabas de teclear hace referencia a unas cuantas variables que no has declarado o definido: protocol, hostname, port, y path. Por eso, añade las siguientes líneas encima de la declaración del método main pero dentro de la declaración de la clase ShowListTest:
private static String protocol = "http";
private static String hostname = "localhost";
private static int port = 8080;
private static String path = "/phonelist/showList.do";
Ya tienes la clase ShowListTest, pero no podrás compilarla o ejecutarlar porque el fichero build.xml no contiene instrucciones pertencientes a los tests. Añade ahora esas instrucciones a build.xml. Primero, necesitamos definir una propiedad que especifique la localización del directorio de la distribución de HttpUnit para poder acceder a los ficheros JAR que contienen las clases. Añade esto al fichero build.xml justo después de la línea que define la propiedad struts.install.dir, que está localizada en la definición del tatget init:
<property name="httpunit.install.dir"
value="/home/wchao/packages/httpunit-1.5.4"/>
Como ya es habitual, reemplaza el valor de la propiedad con la localización de este paquete en tu sistema. Como vas a complar clases Java que hacen uso de las librerías de HttpUnit, necesitarás incluir los ficheros de HttpUnit en el classpath. Añade las siguientes líneas al fichero build.xml justo después de la línea que dice <property name="classpath" refid="base.path"/>:
<path id="test.lib.path">
<path refid="base.path"/>
<fileset dir="${httpunit.install.dir}/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${httpunit.install.dir}/jars">
<include name="*.jar"/>
</fileset>
</path>
<property name="test.lib.classpath" refid="test.lib.path"/>
Más adelante usarás la propiedad test.lib.classpath para proporcionar acceso a las librerías de HttpUnit durante la compilación de las clases de tests. Ahora añade, el siguiente target a build.xml justo después del target llamado compile-classes:
<target name="compile-tests" depends="init, create-unpacked-layout-dirs">
<mkdir dir="${build.dir}/test"/>
<javac destdir="${build.dir}/test"
debug="on"
deprecation="on"
optimize="off"
source="1.4">
<src path="${src.dir}/test"/>
<classpath path="${test.lib.classpath}"/>
</javac>
</target>
Este target compila las clases de tests localizadas en el directorio src/test del proyecto phonelist. Hace uso de la propiedad test.lib.classpath que acabas de definir para permitir que el compilador resuelva las referencias a las librerías HttpUnit.
Ahora necesitas algunos targets para ejecutar los tests. Añade el siguiente fragmento de XML al fichero build.xml justo después de la definición del target deploy:
<target name="test"
depends="compile-tests, post-compile-tests-init, test-showlist"
description="Run all tests"/>
<target name="test-showlist" depends="compile-tests, post-compile-tests-init"
description="Run showlist test">
<java classname="com.abcinc.phonelist.test.ShowListTest">
<classpath path="${test.complete.classpath}"/>
</java>
</target>
Defines el target test para poder ejecutar todos los tests con un sólo comando. Tendrás que seguir añadiendo atributos depends al arget test según vayas añadiendo más tests. El target test-showlist simplemente ejecuta el test showlist. Podrías observar que los targets que acabas de definir tratan con un target y una propiedad que todavía no existen (post-compile-tests-init y test.complete.classpath, respectivamente). En post-compile-tests-init, defines la propiedad test.complete.classpath para poder utilizarla como classpath en el target test-showlist. La razón por la que se define la propiedad test.complete.classpath de forma separada en post-compile-tests-init en vez de en el target init es que las clases de tests todavía no se han compilado cuando se ejecuta el target init. Por lo tanto, definir un path que incluya clases de tests no funcionará porque Ant espera definiciones de paths que existan. Por eso, se añade el target post-compile-tests-init. Añade el siguiente código XML al fichero build.xml después del target compile-tests:
<target name="post-compile-tests-init" depends="init">
<path id="test.complete.path">
<path refid="test.lib.path"/>
<dirset dir="${build.dir}/test">
<include name="**"/>
</dirset>
</path>
<property name="test.complete.classpath" refid="test.complete.path"/>
</target>
En este punto, tu fichero build.xml proporciona suficiente información para que Ant pueda realizar la construcción de la aplicación Web. También le has dicho a Ant que realice la construcción de los tests y que los ejecute.