Construir una Aplicacion Web utilizando HttpUnit y la Metodología Diriga al Test

Ahora procederemos a través del ciclo de desarrollo utilizando HttpUnit. Empieza con la idea de construir un listín de teléfonos electrónico. Tu primer paso de implementación (es decir, la parte que va después de la solicitación de requerimientos y del diseño de la aplicación) debería ser crear el árbol de directorios y escribir un fichero build.xml fundacional para poder empezar a codificar y testear.

Primero, borra el árbol de directorios phonelist y el archivo phonelist.tgz con los siguientes comandos:

rm -fr ~/projects/phonelist
rm -f ~/phonelist.tgz

Ahora estámos en el mismo punto como si acabaramos de empezar un proyecto de software. Crea el árbol de directorios para contener los ficheros que crearemos con los siguientes comandos:

mkdir ~/projects/phonelist
cd ~/projects/phonelist
mkdir src
mkdir src/web
mkdir src/WEB-INF
mkdir src/WEB-INF/classes
mkdir src/WEB-INF/classes/com
mkdir src/WEB-INF/classes/com/abcinc
mkdir src/WEB-INF/classes/com/abcinc/phonelist
mkdir src/test
mkdir src/test/com
mkdir src/test/com/abcinc
mkdir src/test/com/abcinc/phonelist
mkdir src/test/com/abcinc/phonelist/test

El siguiente paso es crear un fichero build.xml rudimentario que podamos desarrollar de forma incremental y probar con simples comandos de una línea que realicen la construcción y testeos automáticos. Teclea lo siguiente en un fichero llamado build.xml en el directorio ~/projects/phonelist:

<project name="Phone List Application" basedir=".">
  <target name="init">
    <property name="tomcat.install.dir" value="/home/wchao/packages/jakarta-tomcat-4.1.27"/>
    <property name="struts.install.dir" value="/home/wchao/packages/jakarta-struts-1.1"/>
    <property name="src.dir" value="${basedir}/src"/>
    <property name="build.dir" value="${basedir}/build"/>
    <property name="war.base.name" value="phonelist"/>
    <property name="deploy.dir" value="${tomcat.install.dir}/webapps"/>
    <path id="base.path">
      <fileset dir="${tomcat.install.dir}/common/lib">
        <include name="*.jar"/>
      </fileset>
      <fileset dir="${struts.install.dir}/lib">
        <include name="*.jar"/>
      </fileset>
    </path>
    <property name="classpath" refid="base.path"/>
  </target>
</project>

Asegurate de cambiar los valores de las propiedades tomcat.install.dir y struts.install.dir para que reflejen las localizaciones adecuadas de Tomcat y Struts. Graba lo que tienes ahora. Acabas de teclear un target de inicialización (target, como podrías recordar, es un término de Ant para indicar una serie de instrucciones relacionadas empaquetadas como una unidad). El taget init define las propiedades que utilizarás más adelante, como la localización de Tomcat, la localización de librerías externas y la localización de los ficheros fuente.

. Definir Targets para tu Aplicación Web

Ahora define algunos targets Ant que realmente realicen acciones. Para una aplicación Web, como mínimo deberias poder realizar estas dos tareas:

  1. Limpiar el directorio, borrando cualquier fichero compilado o copiado para poder empezar de nuevo sólo desde el código fuente.
  2. Compilar y desplegar la aplicación en el Servidor Web (Tomcat en este caso).

La primera tarea que definirás en build.xml es un target llamado clean que limpiará el árbol de directorios para empezar una construcción desde cero. La segunda tarea que definirás será el target llamado deploy que compilará las clases, empaquetará las clases junto con otros ficheros Web y los descriptores en un fichero WAR, y luego desplegará el fichero WAR en el servidor Web. Además definirás una tercera tarea llamada package-war que compilará todas las clases y las empaquetará junto a los ficheros Web no procesados (JSP, imágenes, ficheros de propiedades, etc.) en un fichero WAR que se puede desplegar en el directorio de despliegue de Tomcat (normalmente llamado webapps en las distribuciones estándar de Tomcat). El target package-war solo hace visibles y públicos los pasos intermedios de compilar y empaquetar los ficheros en un fichero WAR. El target deploy termina llamando al target package-war.

El target clean es bastante sencillo de codificar. Situa el siguiente fragmento de XML directamente después de la etiqueta </target> que cierra el elemento <target name="init"> pero antes de la etiqueta de cierre </project>:

  <target name="clean" depends="init" description="Clean build directory tree">
    <delete dir="${build.dir}"/>
  </target>

El target deploy es más complicado, por eso lo vamos a dividir en varios pasos. Necesita hacer lo siguiente:

  1. Compilar los servlets y otras clases Java.
  2. Ensamblar las clases compiladas y los ficheros no procesados (como JSPs, imágenes, hojas de estilo, y descriptores de despliegue XML) en un fichero WAR.
  3. Desplegar la aplicación copiando el fichero WAR en el directorio de Tomcat.

Compilar las clases Java y luego ensamblarlas con los ficheros no procesados en un fichero WAR se puede agrupar lógicamente en un target package-war. Los usuarios podrán invocar directamente este target desde Ant.

Una buena forma de imaginar qué targets deberías crear es trabajar hacia atrás desde tu objetivo. Tu quieres desplegar un fichero WAR en Tomcat, eso significa que necesitas un fichero WAR con todos los ficheros de la aplicación empaquetados. La forma más fácil de crear un fichero WAR es comprimir un árbol de directorios con la distribución de ficheros que corresponda con el fichero WAR deseado. Recuerda que un fichero WAR simplemente es un fichero ZIP con una reglas específicas sobre qué ficheros necesitan estar presentes y dónde deberían ir ciertos ficheros en el árbol de directorios. Para crear el árbol de directorios con la distribución descomprimida y el contenido de ficheros, sigue estos pasos:

  1. Consfigura los directorios para tener un lugar donde poner los ficheros.
  2. Copia los ficheros que no necesitan procesamiento en el árbol de directorios descomprimido. Esto imcluirá las páginas JSP, los ficheros descritpores XML, las imágenes y otros tipos MIME.
  3. Compila las clases. El código final se graba directamente en el árbol de directorios descomprimido.

Para configurar los directorios, introduce el siguiente fragmento en build.xml debajo del target clean que acabas de crear:

  <target name="create-unpacked-layout-dirs" depends="init">
    <mkdir dir="${build.dir}/unpacked-layout"/>
    <mkdir dir="${build.dir}/unpacked-layout/WEB-INF"/>
    <mkdir dir="${build.dir}/unpacked-layout/WEB-INF/classes"/>
    <mkdir dir="${build.dir}/unpacked-layout/WEB-INF/lib"/>
  </target>

Todas las JSPs, las imágenes, las hojas de estilo y otros ficheros que no necesitan compilación van directamente en el directorio unpacked-layout. Los descriptores de despliegue van en unpacked-layout/WEB-INF. Los ficheros de clases Java van en unpacked-layout/WEB-INF/classes. Los ficheros JAR de tus librerías van en unpacked-layout/WEB-INF/lib.

El siguiente paso es copiar los ficheros que no necesitan compilación en el árbol unpacked-layout. Teclea lo siguiente en build.xml debajo del target create-unpacked-layout-dirs:

  <target name="copy-unprocessed-files" depends="init, create-unpacked-layout-dirs">
    <copy todir="${build.dir}/unpacked-layout">
      <fileset dir="${src.dir}/web">
        <include name="**"/>
      </fileset>
    </copy>
    <copy todir="${build.dir}/unpacked-layout/WEB-INF">
      <fileset dir="${src.dir}/WEB-INF">
        <exclude name="classes/**"/>
        <include name="**"/>
      </fileset>
      <fileset dir="${struts.install.dir}/lib">
        <include name="*.tld"/>
        <include name="*.xml"/>
      </fileset>
    </copy>
    <copy todir="${build.dir}/unpacked-layout/WEB-INF">
      <fileset dir="${src.dir}/WEB-INF">
        <include name="classes/**/*.properties"/>
      </fileset>
      <fileset dir="${src.dir}/WEB-INF">
        <include name="classes/**/*.xml"/>
      </fileset>
    </copy>
    <copy todir="${build.dir}/unpacked-layout/WEB-INF/lib">
      <fileset dir="${struts.install.dir}/lib">
        <include name="*.jar"/>
      </fileset>
    </copy>
  </target>

Este target primero copia los ficheros Web como páginas JSP directamente en unpacked-layout, luego copia los descriptores XML en unpacked-layout/WEB-INF. Después de esto, copia las propiedades, recursos y otros ficheros de recursos dentro de unpacked-layout/WEB-INF/classes, y por último copia los ficheros JAR en unpacked-layout/WEB-INF/lib.

Ahora volvamos a los ficheros que requieren compilación. Añade el siguiente fragmento de código XML a build.xml después del target copy-unprocessed-files:

  <target name="compile-classes" depends="init, create-unpacked-layout-dirs">
    <javac destdir="${build.dir}/unpacked-layout/WEB-INF/classes"
           debug="on"
           deprecation="on"
           optimize="off"
           source="1.4">
      <src path="${src.dir}/WEB-INF/classes"/>
      <classpath path="${classpath}"/>
    </javac>
  </target>

Este target compila todas las clases del directorio WEB-INF/classes del árbol de código fuente. Recuerda que la localización del árbol de código fuente se especificó en el target init. La localización se situó en una propiedad global llamada src.dir. El compilador utiliza el classpath especificado en el target init. Los ficheros compilados se sitúan en el directorio unpacked-layout/WEB-INF/classes.

. Agrupar los Targets

Crea un nuevo target que agrupe los tres que acabas de crear. El nuevo target se llamará build-unpacked, y es muy corto. Introduce el siguiente código bajo el target compile-classes:

  <target name="build-unpacked"
       depends="init, create-unpacked-layout-dirs, copy-unprocessed-files, compile-classes"/>

El target está vacío. Sólo invoca al target init para inicializar las propiedades y a los otros tres targets que acabas de crear. Ahora tienes la habilidad de construir toda la aplicación y distribuir los ficheros según ordena el estándar WAR.

El siguiente paso obvio es convertir la distribución descomprimida en un WAR antes de desplegar el WAR en Tomcat. El siguiente fragmento de build.xml crea un directorio donde situar el fichero WAR:

  <target name="create-deploy-dir" depends="init">
    <mkdir dir="${build.dir}/deploy"/>
  </target>

Deberías introducir este targer justo después del target build-unpacked que acabas de crear. Ahora tienes una distribución descomprimida de ficheros y un lugar para almacenar el fichero WAR.

El siguiente paso es crear el fichero WAR. Los ficheros WAR deben adherirse a una distribución definida. Pon el siguiente fragmento de código XML en build.xml justo después del target create-deploy-dir:

  <target name="package-war"
          depends="init, build-unpacked, create-deploy-dir"
          description="Build all the files and package them into a WAR file">
    <war warfile="${build.dir}/deploy/${war.base.name}.war"
         webxml="${build.dir}/unpacked-layout/WEB-INF/web.xml">
      <webinf dir="${build.dir}/unpacked-layout/WEB-INF">
        <include name="**"/>
        <exclude name="web.xml"/>
        <exclude name="classes/**"/>
        <exclude name="lib/**"/>
      </webinf>
      <classes dir="${build.dir}/unpacked-layout/WEB-INF/classes">
        <include name="**"/>
      </classes>
      <lib dir="${build.dir}/unpacked-layout/WEB-INF/lib">
        <include name="**"/>
      </lib>
      <fileset dir="${build.dir}/unpacked-layout">
        <include name="**"/>
        <exclude name="WEB-INF/**"/>
      </fileset>
    </war>
  </target>

Este target hace uso del target build-unpacked para crear la distribución descomprimida y el target create-deploy-dir para crear el directorio para el fichero WAR. El propio target package-war sólo tiene una instrucción: war, que crea un fichero WAR y especifica la localización del directorio WEB-INF, el directorio classes, el directorio lib, y los ficheros no procesados. En este punto tenemos la habilidad de generar un fichero WAR capaz de ser desplegado en Tomcat.

El siguiente paso es copiar el fichero en el directorio de despliegue de Tomcat para que éste pueda desplegar la aplicación. El siguiente fragmento XML copia el fichero WAR en el directorio de despliegue de Tomcat:

  <target name="copy-war" depends="package-war">
    <copy file="${build.dir}/deploy/${war.base.name}.war" todir="${deploy.dir}"/>
  </target>

Introduce el target copy-war justo después del target package-war. Para unir estos dos targets en una función de despligue útil, crea otro target que simplemente llame al target package-war seguido por el target copy-war. LLámalo deploy. Teclea lo siguiente en el fichero build.xml después del target copy-war:

  <target name="deploy" depends="package-war, copy-war" 
     description="Deploy application to Tomcat"/>

El target deploy no contiene ninguna instrucción real. Simplemente llama a otros targets para relizar el trabajo.

Deberías crear un target undeploy para poder eliminar una vieja versión de la aplicación phonelist antes de desplegar una nueva version que resulte de los cambios que puedas hacer al código. Tomcat no borra automáticamente el directorio desempaquetado o el archivo WAR cuando lo apagas. Además, Tomcat no detecta los cambios en el archivo WAR, por eso no despliega automáticamente nuevas versiones de una aplicación cuando se copian nuevos ficheros WAR sobre los viejos en el directorio de despliegue de Tomcat (excepto en el caso de específicarlo estáticamente en el fichero de configuración server.xml de Tomcat). Por estas razones es importante tener un target undeploy en el fichero build.xml. Añade el siguiente fragmento de XML después del target deploy:

  <target name="undeploy" depends="init" description="Undeploy the application from Tomcat">
    <delete dir="${deploy.dir}/${war.base.name}"/>
    <delete file="${deploy.dir}/${war.base.name}.war"/>
  </target>

Como ahora tienes targets que funcionan en tu fichero de construcción Ant, deberías cambiar el target por defecto. Actualmente tienes esto en tu fichero build.xml:

<project name="Phone List Application" basedir=".">

Deberías cambiarlo por lo siguiente:

<project name="Phone List Application" default="package-war" 
     basedir=".">

En este punto, tienes un fichero de construcción con la habilidad de compilar y desplegar la aplicación con una sóla línea de comando. La construcción automática será esencial durante el proceso de desarrollo. Mira el fichero build.xml incluido en el código de ejemplo. El fichero build.xml se llama build.xml.v1. Esencialmente es el mismo que acabas de crear, pero tiene las cosas en un orden diferente que lo hacen más fácil de leer y de mantener.

Podrías elegir utilizar el fichero build.xml.v1 como tu base para avanzar, pero no tienes porque hacerlo. Le añadirás más código XML para añadir tests. Si eliges utilizarlo, asegurate de renombarlo como build.xml después de copiarlo al directorio ~/projects/phonelist.

COMPARTE ESTE ARTÍCULO

ENVIAR A UN AMIGO
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN GOOGLE +
SIGUIENTE ARTÍCULO

¡SÉ EL PRIMERO EN COMENTAR!
Conéctate o Regístrate para dejar tu comentario.