Zona HTML Zona Java Zona PHP Zona ASP Zona Bases de datos
Inicio > Tutoriales > Lenguajes orientados a objeto > Java > J2EE > Construir una Aplicacion Web utilizando HttpUnit y la Metodología Diriga al Test
-Tutoriales

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


Añadir Contactos

. Crear los Tests para la Función "New Contact"

La característica "new contact" está accesible en http://localhost:8080/phonelist/new.do. Esta URL debería mostrar una página con un formulario que acepte la entrada de las propiedades de un contacto: last name, first name, phone, fax, y email. También necesitarás una action que haga lo siguiente:

  1. Acepte los datos introducidos por el usuario en el navegador.
  2. Cree un nuevo ejemplar de ContactBean con un valor de ID único.
  3. Almacene el bean en el repositorio ContactDatabase.

La clase NewTest debería testear las siguientes condiciones o funcionalidades:

  1. En la página mostrada por la acción /showList.do, hay un enlace titulado "Create New Contact" que apunta a /new.do.
  2. En la página new contact, hay un formulario con los campos last name, first name, phone, fax, y email que tiene un atributo action apuntando a /save.do.
  3. Cuando se envía un contacto con datos aleatorios para los campos, los datos recien creados se muestran en la página que muestra la acción showList.do. Además, el número contactos se aumenta en uno.

Teclea el siguiente código en un fichero llamado NewTest.java en el directorio src/WEB-INF/classes/com/abcinc/phonelist:


package com.abcinc.phonelist.test;

import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.TableCell;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class NewTest extends TestCase {

  private static String protocol = "http";
  private static String hostname = "localhost";
  private static int port = 8080;
  private static String showListPath = "/phonelist/showList.do";
  private static String newPath = "/phonelist/new.do";

  private WebConversation webConversation = new WebConversation();

  public static void main(String args[]) {
    junit.textui.TestRunner.run(suite());
  }      

  public static TestSuite suite() {
    return new TestSuite(NewTest.class);
  }      

  public NewTest(String s) {
    super(s);
  }      

  public void testShowListHasNewContactLink() throws Exception {
    String url = protocol + "://" + hostname + ":" + port + showListPath;
    WebRequest webRequest = new GetMethodWebRequest(url);
    WebResponse webResponse = webConversation.getResponse(webRequest);
    WebTable webTable = webResponse.getTableStartingWith("Phone List");
    assertNotNull("Phone List HTML table not found", webTable);
    int rowCount = webTable.getRowCount();
    TableCell lastTableCell = webTable.getTableCell(rowCount - 1, 0);
    WebLink webLink = lastTableCell.getLinkWith("New Contact");
    String linkUrl = webLink.getURLString();
    if (linkUrl.indexOf(";jsessionid=") >= 0) {
      linkUrl = linkUrl.substring(0, linkUrl.indexOf(";jsessionid="));
    }
    assertTrue("Phone List has no new contact link", linkUrl.endsWith(newPath));
  }

}

Este clase debería parecerte familar. Es similar a la clase ShowListTest que vimos en páginas anteriores. La clase NewTest realizará los tests que hemos visto en el listado anterior. Ahora mismo sólo realiza el primero de los tres tests. Podrías comparar tu fichero NewTest.java con NewTest.java.v1 del archivo del código de ejemplo. El fichero NewTest.java.v1 contiene comentarios útiles, podrías echarle un vistazo aunque pienses utilizar el fichero que acabas de crear.

Para el nuevo test, también necesitarás añadir un target al fichero build.xml incluido en el archivo del código de ejemplo. Deberías copiar build.xml.v2 desde el archivo del código de ejemplo a tu directorio ~/projects/phonelist. Luego, añade la siguiente definición de target debajo del target test-showlist:

  <target name="test-new" depends="compile-tests, post-compile-tests-init"
      description="Run new test">
    <java classname="com.abcinc.phonelist.test.NewTest">
      <classpath path="${test.complete.classpath}"/>
    </java>
  </target>

Además, necesitas modificar la definición existente del target test para adjuntarle la definición de test-new. Reemplaza la definición existente del target test con ésta:

  <target name="test"
          depends="compile-tests, post-compile-tests-init, test-showlist, test-new"
          description="Run all tests"/>

Tu fichero build.xml debería parecerse al fichero build.xml.v3 del archivo del código de ejemplo, con la excepción de los comentarios y posiblemente el formateo. Podrías adoptar build.xml.v3 como tu fichero build.xml si quieres asegurarte de que has realizado todos los cambios descritos arriba.

Ejecuta los test tecleando ant test. Este comando ejecutará tanto el test showlist como el nuevo test para segurarse que se prueban las viejas funcionalidades. Cualquier cambio en las funcionalidades no solo provoca que se testeen las nuevas funcionalidades sino que también evita la rotura de las viejas funcionalidades.

Debería pasarse con éxito el test showlist. En este punto también debería pasarse el nuevo test, pero no hemos finalizado la codificción de los otros dos tests de la suite de tests new contact. Después de implementar los otros dos tests, la suite de tests NewTest debería fallar porque todavía no has implementado la funcionalidad new contact. Implementa los dos tests restantes para entonces poder implementar la funcionalidad que deben testear estos tests.

Añade esto en la parte superior del fichero NewTest.java junto a las otras sentencias import:

import com.meterware.httpunit.SubmitButton;
import com.meterware.httpunit.WebForm;
import java.util.Random;

Añade también esto a NewTest.java después de la línea que dice: private static String newPath = "/phonelist/new.do":

  private static String savePath = "/phonelist/save.do";
  private static String randomCharacterSet =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

La variable randomCharacterSet se utiliza para generar strings aleatorios que se utilizan para verificar que la aplicación está grabando los nuevos contactos. Añade también la siguiente declaración de variable estática a la declaración de webConversation:

  private static Random random = new Random();

Añade los métodos del siguiente listado a NewTest.java:


    public void testNewContactForm() throws Exception {
        String url = protocol + "://" + hostname + ":" + port + newPath;
        WebRequest webRequest = new GetMethodWebRequest(url);
        WebResponse webResponse = webConversation.getResponse(webRequest);
        WebForm webForm = webResponse.getFormWithID("contactForm");
        // test that the contact form exists.
        assertNotNull("Contact form not found", webForm);
        // test that the required fields exist on the form.
        assertTrue("Last Name field (lastName) missing from contact form", 
                  webForm.hasParameterNamed("lastName"));
        assertTrue("First Name field (firstName) missing from contact form",
                  webForm.hasParameterNamed("firstName"));
        assertTrue("Phone field (phone) missing from contact form", 
                  webForm.hasParameterNamed("phone"));
        assertTrue("Fax field (fax) missing from contact form", 
                  webForm.hasParameterNamed("fax"));
        assertTrue("Email field (email) missing from contact form", 
                  webForm.hasParameterNamed("email"));
        // test that the form action points to the save action.
        String formAction = webForm.getAction();
        // strip off session state information in the URL if it is there
        // because we want to compare the path of the URL.
        if (formAction.indexOf(";jsessionid=") >= 0) {
            formAction = formAction.substring(0, formAction.indexOf(";jsessionid="));
        }
        assertTrue("Contact form points to wrong action", formAction.endsWith(savePath));
    }

    // test that we can save a new contact.
    public void testSaveNewContact() throws Exception {
        String url;
        WebRequest webRequest;
        WebResponse webResponse;
        
        // first get the existing list of contacts so we can count how
        // many contacts there are. We use the information later to
        // compare the number of contacts after saving a new contact.
        url = protocol + "://" + hostname + ":" + port + showListPath;
        webRequest = new GetMethodWebRequest(url);
        webResponse = webConversation.getResponse(webRequest);
        WebTable webTable = webResponse.getTableStartingWith("Phone List");
        int rowCount = webTable.getRowCount();
        // subtract the three rows for title, column headings, and buttons.
        int numContacts = rowCount - 3;
        TableCell lastBodyCell = webTable.getTableCell(rowCount - 2, 0);
        if (lastBodyCell.getColSpan() > 1) {
            // this means the message that there were no contacts was
            // displayed.
            numContacts = 0;
        }
        // now retrieve the new contact form page.
        url = protocol + "://" + hostname + ":" + port + newPath;
        webRequest = new GetMethodWebRequest(url);
        webResponse = webConversation.getResponse(webRequest);
        WebForm webForm = webResponse.getFormWithID("contactForm");
        // test that the contact form exists.
        assertNotNull("Contact form not found", webForm);
        String lastName = getRandomString(8);
        String firstName = getRandomString(8);
        String phone = getRandomString(8);
        String fax = getRandomString(8);
        String email = getRandomString(8);
        webForm.setParameter("lastName", lastName);
        webForm.setParameter("firstName", firstName);
        webForm.setParameter("phone", phone);
        webForm.setParameter("fax", fax);
        webForm.setParameter("email", email);
        // find the save button (rather than the cancel button).
        SubmitButton saveButton = webForm.getSubmitButton("submitButton", 
             "        Save     ");
        // make sure the save button exists.
        assertNotNull("Could not find save button", saveButton);
        webResponse = webForm.submit(saveButton);
        // now parse the results after saving the contact.
        webTable = webResponse.getTableStartingWith("Phone List");
        int newRowCount = webTable.getRowCount();
        // subtract the three rows for title, column headings, and buttons.
        int newNumContacts = newRowCount - 3;
        lastBodyCell = webTable.getTableCell(rowCount - 2, 0);
        if (lastBodyCell.getColSpan() > 1) {
            // this means the message that there were no contacts was
            // displayed.
            newNumContacts = 0;
        }
        assertTrue("Saving new contact did not increase contact count by 1", 
               (newNumContacts == (numContacts + 1)));
        // test that the random data we generated matches the contact
        // information by trying to find a row with matching field values.
        boolean foundMatchingContact = false;
        for(int i = 0; i < newNumContacts; i++) {
            // first two rows are table title and heading columns
            int rowIndex = i + 2;
            // get the last name
            TableCell tableCell = webTable.getTableCell(rowIndex, 2);
            String columnValue = tableCell.asText();
            if (columnValue.equals(lastName)) {
                tableCell = webTable.getTableCell(rowIndex, 3);
                columnValue = tableCell.asText();
                if (!columnValue.equals(firstName)) continue;
                tableCell = webTable.getTableCell(rowIndex, 4);
                columnValue = tableCell.asText();
                if (!columnValue.equals(phone)) continue;
                tableCell = webTable.getTableCell(rowIndex, 5);
                columnValue = tableCell.asText();
                if (!columnValue.equals(fax)) continue;
                // email has an extra space at the beginning and an extra
                // space at the end, so we need to strip those.
                tableCell = webTable.getTableCell(rowIndex, 6);
                columnValue = tableCell.asText();
                columnValue = columnValue.substring(1, columnValue.length() - 1);
                if (!columnValue.equals(email)) continue;
                foundMatchingContact = true;
                break;
            }
        }
        assertTrue("Newly created contact was not saved properly", foundMatchingContact);
    }

    // generate a random string of the specified length.
    private String getRandomString(int length) {
        StringBuffer randomStringBuffer = new StringBuffer();
        for(int i = 0; i < length; i++) {
            int index = random.nextInt(randomCharacterSet.length());
            randomStringBuffer.append(randomCharacterSet.substring(index, index + 1));
        }
        return randomStringBuffer.toString();
    }

El método testNewContactForm verifica que existe el formulario new contact, que contiene los campos que se requieren, y que tiene configurada la action apropiada.

El método testSaveNewContact es un poco más complejo. Calcula el número filas de la lista de contactos, luego recupera el formulario new contact y simula el proceso de rellenado de los campos del formulario con strings completamente aleatorios de ocho caracteres para los campos last name, first name, phone, fax, y email. Luego simula que el usuario ha pulsado el botón Save. Como existen los botones Save y Cancel, es importante simular la pulsación del botón apropiado. Finalmente, analiza la respuesta de saving the contact, que debería ser la página showList. Chequea que el número de contactos se ha incrementado en uno y que uno de los contactos corresponde con el recientemente introducido.

El método getRandomString simplemente es un método de ayuda que genera un string aleatorio de la longitud especificada por un parámetro. El método testSaveNewContact lo llama para generar los valores de los diferentes campos.

En este punto, tu fichero NewTest.java debería parecerse al NewTest.java.v2 del archivo del código de ejemplo, con la excepción de los comentarios y posiblemente el formateo.

Ejecuta los tests ahora. La suite showlist debería pasarse completamente, pero el test new sólo se pasará parcialmente. Dos de los tres test de la suite fallarán debido a la falta de la acción /new.do. Recbirás un mensaje de error similar a Este:

 
     [java] 2) testSaveNewContact(com.abcinc.phonelist.test.NewTest)com.meterware.httpunit.HttpException:
 Error on HTTP request: 400 Invalid path /new was requested [http://localhost:8080/phonelist/new.do]

. Implementar la Función "New Contact"

Implementa la funcionalidad new contact para que la aplicación pase la suite de tests NewTest además de ShowListTest. Los ficheros que tendrás que crear o modificar son:

  1. NewAction.java
  2. EditForm.java
  3. edit.jsp
  4. struts-config.xml
  5. tiles-defs.xml
  6. ApplicationResources.properties

La clase NewAction simplemente rellena la clase EditForm con valores por defecto y luego muestra el JSP que contiene el HTML del formulario. Algunos formularios contienen valores por defecto. En nuestro caso no existen los valores por defecto.

La clase EditForm es un contenedor para pasar datos entre la capa de persistencia (las clases JaveBean que modelan los datos en la base de datos) y la capa de presentación (los formularios JSP o HTML que muestran la información y aceptan entrada desde un navegador). La razón por la que esto es útil en las clases de formularios de Struts es porque la capa de persistencia muchas veces tiene diferencias con los tipos de datos o su orden en la capa de presentación. Como ejemplo concreto, consideremos el caso de un valor de fecha. En la mayoría de bases de datos, una fecha se almacena como un único campo que contiene el mes, el día y el año. En Java, se almacena una fecha en un objeto java.util.Date. La mayoría de gente piensa que es más fácil introducir las fechas con tres campos desplegables o con dos campos desplegables y un campo de texto. El mes y el día usualmente son campos desplegables. Y ocasionalmete el año también es un campo desplegable, pero algunas veces es un campo de texto. Incluso si le pides a un usuario que introduzca la fecha como un único campo, todavía tendrás que tratar con la conversión de tipos porque los formularios Web estándars sólo pueden transmitir datos strings.

El fichero edit.jsp contiene el HTML para el formulario, incluyendo la sección superior para mostrar los mensajes de error y las etiquetas de Struts para mostrar campos de entrada HTML. La razón de utilizar edit.jsp en lugar de utilizar un fichero separado llamado new.jsp es que el formulario para crear un nuevo contacto es exactamente el mismo que el formulario para crear un contacto existente, con algunas excepciones:

  1. El formulario new contact no tiene un valor para el campo oculto ID que identifica el registro que se está editando.
  2. El formulario new contact podría tener un título diferentes o una cabecera de tabla diferente al formulario edit contact (por ejemplo, "New Contact" vs. "Edit Contact").

Realiza los siguiente cambios:

  1. Copia NewAction.java.v1 desde el archivo del código de ejemplo a src/WEB-INF/classes/com/abcinc/phonelist y llamalo NewAction.java.
  2. Copia también EditForm.java.v1 a src/WEB-INF/classes/com/abcinc/phonelist y llamalo EditForm.java.
  3. Copia edit.jsp.v1 a src/web y llamalo edit.jsp.
  4. Añade la siguiente sección al fichero struts-config.xml en la sección form-bean justo después de la entrada para manageForm:
        <form-bean name="editForm"
                   type="com.abcinc.phonelist.EditForm"/>
    
  5. Añade las siguientes secciones al fichero struts-config.xml en la sección action-mapping:
        <action path="/new"
                type="com.abcinc.phonelist.NewAction"
                name="editForm"
                scope="request"
                input="success"
                validate="false">
          <forward name="success" path="edit"/>
        </action>
        
        <action path="/save"
                type="com.abcinc.phonelist.SaveAction"
                name="editForm"
                input="inputProblem"
                scope="request"
                validate="true">
          <forward name="inputProblem" path="edit"/>
          <forward name="success" path="showList"/>
          <forward name="cancel" path="showList"/>
        </action>
    

    La razón por la que necesitas definir ahora /save es porque lo utilizas en el atributo action del formulario HTML de edit.jsp.

  6. Añade la siguiente sección a tiles-defs.xml:
      <definition name="edit" extends="mainLayout">
        <put name="titleString" value="Phone List :: Edit Contact"/>
        <put name="body" value="/edit.jsp"/>
        <put name="bodyParam1" value="Edit" direct="true"/>
      </definition>
    
  7. Copia ApplicationResources.properties.v1 desde el archivo del código de ejemplo a src/WEB-INF/classes/com/abcinc/phonelist y llamalo ApplicationResources.properties. Este fichero almacena strings de recursos para Struts, principalmente etiquetas de campos y mensajes de error. Tener todas estas etiquetas, mensajes de error y otros textos visibles en un fichero hace más fácil internacionalizar la aplicación. Para poder crear una versión en Ruso, Frances, o Alemán, por ejemplo, todo lo que tienes que hacer es traducir los textos y crear un fichero ApplicationResources.properties separado (con un sufijo que denote la localidad). La aplicación Web usará automáticamente el fichero apropiado basándose en la localidad.

En este punto, tu fichero struts-config.xml debería ser equivalente a struts-config.xml.v3 del archivo del código de ejemplo. Al igual que tu fichero tiles-defs.xml debería ser equivalente a tiles-defs.xml.v3.

Ahora realiza los siguientes pasos:

  1. Para Tomcat tecleando ./shutdown.sh en el subdirectorio bin de la distribución de Tomcat.
  2. Ejecuta ant undeploy.
  3. Ejecuta ant deploy.
  4. Arranca Tomcat tecleando ./startup.sh en el subdirectorio bin de la distribución de Tomcat.

Pasa de nuevos los tests tecleando ant test. La mayoría de los tests deberían pasarse, con la excepción de testSaveNewContact en la suite NewTest. Esto es natural ya que todavía no has implementado SaveAction. Los tests están diseñados para capturar cosas como estas.

Vuelve atrás y remedia el problema realizando los siguientes pasos:

  1. Copia SaveAction.java.v1 desde el archivo del código de ejemplo a src/WEB-INF/classes/com/abcinc/phonelist y llamalo SaveAction.java.
  2. Copia también validation.xml.v2 a src/WEB-INF y llamalo validation.xml, reemplazanto tu versión existente de validation.xml. Aunque no es necesario, esto ayuda con el chequeo de entradas en los formularios para asegurarnos que se introducen los valores correctos. La validación en este momento sólo consiste en comprobar que se han introducido el nombre y los apellidos.

Ahora vuelve a ejecutar los tests teclando ant test en el directorio del proyecto phonelist. Todos los tests deberían pasarse con éxito.

 
Patrocinados
 

Copyright © 1999-2006 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network