package com.tuempresa.facturacion.pruebas;
import org.openxava.tests.*;
public class PruebaCliente extends ModuleTestBase { // Ha de extender de ModuleTestBase
public PruebaCliente(String nombrePrueba) {
super(nombrePrueba, "facturacion", // Indicamos el nombre de aplicación (facturacion)
"Cliente"); // y nombre de módulo (Cliente)
}
// Los métodos de prueba han de empezar por 'test'
public void testCrearLeerActualizarBorrar() throws Exception {
login("admin", "admin"); // Identificación de usuario para acceder al módulo
// Crear
execute("CRUD.new"); // Pulsa el botón 'Nuevo'
setValue("numero", "77"); // Teclea 77 como valor para el campo 'numero'
setValue("nombre", "Cliente JUNIT"); // Pone valor en el campo 'nombre'
setValue("direccion.viaPublica", "Calle JUNIT"); // Fíjate en la notación del punto
// para acceder al miembro de la referencia
setValue("direccion.codigoPostal", "77555"); // Etc
setValue("direccion.municipio", "La ciudad JUNIT"); // Etc
setValue("direccion.provincia", "La provincia JUNIT"); // Etc
execute("CRUD.save"); // Pulsa el botón 'Grabar'
assertNoErrors(); // Verifica que la aplicación no muestra errores
assertValue("numero", ""); // Verifica que el campo 'numero' está vacío
assertValue("nombre", ""); // Verifica que el campo 'nombre' está vacío
assertValue("direccion.viaPublica", ""); // Etc
assertValue("direccion.codigoPostal", ""); // Etc
assertValue("direccion.municipio", ""); // Etc
assertValue("direccion.provincia", ""); // Etc
// Leer
setValue("numero", "77"); // Pone 77 como valor para el campo 'numero'
execute("CRUD.refresh"); // Pulsa el botón 'Refrescar'
assertValue("numero", "77"); // Verifica que el campo 'numero' tiene un 77
assertValue("nombre", "Cliente JUNIT"); // y 'nombre' tiene 'Cliente JUNIT'
assertValue("direccion.viaPublica", "Calle JUNIT"); // Etc
assertValue("direccion.codigoPostal", "77555"); // Etc
assertValue("direccion.municipio", "La ciudad JUNIT"); // Etc
assertValue("direccion.provincia", "La provincia JUNIT"); // Etc
// Actualizar
setValue("nombre", "Cliente JUNIT MODIFICADO"); // Cambia el valor del campo 'nombre'
execute("CRUD.save"); // Pulsa el botón 'Grabar'
assertNoErrors(); // Verifica que la aplicación no muestra errores
assertValue("numero", ""); // Verifica que el campo 'numero' está vacío
assertValue("nombre", ""); // Verifica que el campo 'nombre' está vacío
// Verifica si se ha modificado
setValue("numero", "77"); // Pone 77 como valor para el campo 'numero'
execute("CRUD.refresh"); // Pulsa en el botón 'Refrescar'
assertValue("numero", "77"); // Verifica que el campo 'numero' tiene un 77
assertValue("nombre", "Cliente JUNIT MODIFICADO"); // y 'nombre' tiene
// 'Cliente JUNIT MODIFICADO'
// Borrar
execute("CRUD.delete"); // Pulsa en el botón 'Borrar'
assertMessage("Cliente borrado satisfactoriamente"); // Verifica que el mensaje
// 'Cliente borrado satisfactoriamente' se muestra al usuario
}
}
...
setValue("numero", "77");
// setValue("nombre", "Cliente JUNIT"); // Comenta esta línea
setValue("direccion.viaPublica", "Calle JUNIT");
...
16-jul-2019 18:03 org.openxava.tests.ModuleTestBase assertNoMessages
SEVERE: Error unexpected: Es ogligado que Nombre en Cliente tenga valor
package com.tuempresa.facturacion.pruebas;
import java.math.*;
import com.tuempresa.facturacion.modelo.*;
import org.openxava.tests.*;
import static org.openxava.jpa.XPersistence.*;
public class PruebaProducto extends ModuleTestBase {
private Autor autor; // Declaramos las entidades a crear
private Categoria categoria; // como miembros de instancia para que
private Producto producto1; // estén disponibles en todos los métodos de prueba
private Producto producto2; // y puedan ser borradas al final de cada prueba
public PruebaProducto(String testName) {
super(testName, "facturacion", "Producto");
}
protected void setUp() throws Exception { // setUp() se ejecuta siempre antes de cada prueba
super.setUp(); // Es necesario porque ModuleTestBase lo usa para inicializarse, JPA se inicializa aquí
crearProductos(); // Crea los datos usados en las pruebas
}
protected void tearDown() throws Exception { // tearDown() se ejecuta
// siempre después de cada prueba
super.tearDown(); // Necesario, ModuleTestBase cierra recursos aquí
borrarProductos(); // Se borran los datos usados en las pruebas
}
public void testBorrarDesdeLista() throws Exception { ... }
public void testSubirFotos() throws Exception { ... }
private void crearProductos() { ... }
private void borrarProductos() { ... }
}
private void crearProductos() {
// Crear objetos Java
autor = new Autor(); // Se crean objetos de Java convencionales
autor.setNombre("JUNIT Author"); // Usamos setters como se suele hacer con Java
categoria = new Categoria();
categoria.setDescripcion("Categoria JUNIT");
producto1 = new Producto();
producto1.setNumero(900000001);
producto1.setDescripcion("Producto JUNIT 1");
producto1.setAutor(autor);
producto1.setCategoria(categoria);
producto1.setPrecio(new BigDecimal("10"));
producto2 = new Producto();
producto2.setNumero(900000002);
producto2.setDescripcion("Producto JUNIT 2");
producto2.setAutor(autor);
producto2.setCategoria(categoria);
producto2.setPrecio(new BigDecimal("20"));
// Marcar los objetos como persistentes
getManager().persist(autor); // getManager() es de XPersistence
getManager().persist(categoria); // persist() marca el objeto como persistente
getManager().persist(producto1); // para que se grabe en la base de datos
getManager().persist(producto2);
// Confirma los cambios en la base de datos
commit(); // commit() es de XPersistence. Graba todos los objetos en la base de datos
// y confirma la transacción
}
import static org.openxava.jpa.XPersistence.*;
...
getManager().persist(autor);
// Gracias al static import de XPersistence es lo mismo que
XPersistence.getManager().persist(autor);
...
commit();
// Gracias al static import de XPersistence es lo mismo que
XPersistence.commit();
private void borrarProductos() { // Llamado desde tearDown()
// por tanto ejecutado después de cada prueba
borrar(producto1, producto2, autor, categoria); // borrar() borra
commit(); // Confirma los cambios en la base de datos, en este caso borrando datos
}
private void borrar(Object ... entidades) { // Usamos argumentos varargs
for (Object entidad : entidades) { // Iteramos por todos los argumentos
getManager().remove(getManager().merge(entidad)); // Borrar(1)
}
}
getManager().persist(autor); // autor está asociado al contexto persistente actual
commit(); // El contexto persistente actual se termina y autor pasa a estar desasociado
getManager().remove(autor); // Falla porque autor está desasociado
autor = getManager().merge(autor); // Reasocia autor al contexto actual
getManager().remove(autor); // Funciona
public void testBorrarDesdeLista() throws Exception {
login("admin", "admin");
setConditionValues("", "JUNIT"); // Establece los valores para filtrar los datos
setConditionComparators("=", "contains_comparator"); // Pone los comparadores para filtrar los datos
execute("List.filter"); // Pulsa el botón para filtrar
assertListRowCount(2); // Verifica que hay 2 filas
checkRow(1); // Seleccionamos la fila 1 (que resulta ser la segunda)
execute("CRUD.deleteSelected"); // Pulsa en el botón para borrar
assertListRowCount(1); // Verifica que ahora solo hay una fila
}
public void testSubirFotos() throws Exception {
login("admin", "admin");
// Buscar producto1
execute("CRUD.new");
setValue("numero", Integer.toString(producto1.getNumero())); // (1)
execute("CRUD.refresh");
assertFilesCount("fotos", 0);
// Subir fotos
uploadFile("fotos", "web/xava/images/add.gif"); // (2)
uploadFile("fotos", "web/xava/images/attach.gif"); // (2)
// Verificar
execute("CRUD.new");
assertFilesCount("fotos", 0);
setValue("numero", Integer.toString(producto1.getNumero())); // (1)
execute("CRUD.refresh");
assertFilesCount("fotos", 2);
assertFile("fotos", 0, "image");
assertFile("fotos", 1, "image");
// Quitar fotos
removeFile("fotos", 1);
removeFile("fotos", 0);
}
package com.tuempresa.facturacion.pruebas;
import org.openxava.tests.*;
public class PruebaAutor extends ModuleTestBase {
public PruebaAutor(String nombrePrueba) {
super(nombrePrueba, "facturacion", "Autor");
}
public void testReadAuthor() throws Exception {
login("admin", "admin");
assertValueInList(0, 0, "JAVIER CORCOBADO"); // El primer autor en la
// lista es JAVIER CORCOBADO
execute("List.viewDetail", "row=0"); // Pulsamos en la primera fila
assertValue("nombre", "JAVIER CORCOBADO");
assertCollectionRowCount("productos", 2); // Tiene 2 productos
assertValueInCollection("productos", 0, // Fila 0 de productos
"numero", "2"); // tiene “2” en la columna “numero”
assertValueInCollection("productos", 0, "descripcion", "Arco iris de lágrimas");
assertValueInCollection("productos", 1, "numero", "3");
assertValueInCollection("productos", 1, "descripcion", "Ritmo de sangre");
}
}
package com.tuempresa.facturacion.pruebas;
import org.openxava.tests.*;
public class PruebaCategoria extends ModuleTestBase {
public PruebaCategoria(String nombrePrueba) {
super(nombrePrueba, "facturacion", "Categoria");
}
public void testCategoriasEnLista() throws Exception {
login("admin", "admin");
assertValueInList(0, 0, "MÚSICA"); // Fila 0 columna 0 tiene “MÚSICA”
assertValueInList(1, 0, "LIBROS"); // Fila 1 columna 0 tiene “LIBROS”
assertValueInList(2, 0, "SOFTWARE"); // Fila 2 columna 0 tiene “SOFTWARE”
}
}
package com.tuempresa.facturacion.pruebas;
import java.time.*;
import java.time.format.*;
import javax.persistence.*;
import org.openxava.tests.*;
import static org.openxava.jpa.XPersistence.*; // Para usar JPA
public class PruebaFactura extends ModuleTestBase {
private String numero; // Para almacenar el número de la factura que probamos
public PruebaFactura(String nombrePrueba) {
super(nombrePrueba, "facturacion", "Factura");
}
public void testCrear() throws Exception { // El método de prueba
login("admin", "admin");
verificarValoresDefecto();
escogerCliente();
anyadirDetalles();
ponerOtrasPropiedades();
grabar();
verificarCreado();
borrar();
}
private void verificarValoresDefecto() throws Exception { … }
private void escogerCliente() throws Exception { … }
private void anyadirDetalles() throws Exception { … }
private void ponerOtrasPropiedades() throws Exception { … }
private void grabar() throws Exception { … }
private void verificarCreado() throws Exception { … }
private void borrar() throws Exception { … }
private String getAnyoActual() { … }
private String getFechaActual() { … }
private String getNumero() { … }
}
private void verificarValoresDefecto() throws Exception {
execute("CRUD.new");
assertValue("anyo", getAnyoActual());
assertValue("numero", getNumero());
assertValue("fecha", getFechaActual());
}
private String getAnyoActual() { // Año actual en formato cadena
return Integer.toString(LocalDate.now().getYear()); // La forma
// típica de hacerlo con Java
}
private String getFechaActual() { // Fecha actual como una cadena
return LocalDate.now().format( // La forma típica de hacerlo con Java
DateTimeFormatter.ofPattern("dd/MM/yyyy"));
}
private String getNumero() { // El número de factura para una factura nueva
if (numero == null) { // Usamos inicialización vaga
Query query = getManager(). // Una consulta JPA para obtener el último número
createQuery("select max(f.numero) from Factura f where f.anyo = :anyo");
query.setParameter("anyo", LocalDate.now().getYear());
Integer ultimoNumero = (Integer) query.getSingleResult();
if (ultimoNumero == null) ultimoNumero = 0;
numero = Integer.toString(ultimoNumero + 1); // Añadimos 1 al
// último número de factura
}
return numero;
}
private void escogerCliente() throws Exception {
setValue("cliente.numero", "1");
assertValue("cliente.nombre", "JAVIER PANIZA"); // El cliente 1 debe de existir en la DB
}
private void anyadirDetalles() throws Exception {
assertCollectionRowCount("detalles", 0); // La colección esta vacía
// Añadir una línea de detalle
setValueInCollection("detalles", 0, // 0 es la primera fila
"producto.numero", "1");
assertValueInCollection("detalles", 0,
"producto.descripcion", "Peopleware: Productive Projects and Teams");
setValueInCollection("detalles", 0, "cantidad", "2");
// Añadir otro detalle
setValueInCollection("detalles", 1, "producto.numero", "2");
assertValueInCollection("detalles", 1, "producto.descripcion", "Arco iris de lágrimas");
setValueInCollection("detalles", 1, "cantidad", "1");
assertCollectionRowCount("detalles", 2); // Ahora tenemos 2 filas
}
private void ponerOtrasPropiedades() throws Exception {
setValue("observaciones", "Esto es una prueba JUNIT");
}
private void grabar() throws Exception {
execute("CRUD.save");
assertNoErrors();
assertValue("cliente.numero", "");
assertCollectionRowCount("detalles", 0);
assertValue("observaciones", "");
}
private void verificarCreado() throws Exception {
setValue("anyo", getAnyoActual()); // El año actual en el campo año
setValue("numero", getNumero()); // El número de la factura usada en la prueba
execute("CRUD.refresh"); // Carga la factura desde la base de datos
// En el resto de la prueba confirmamos que los valores son los correctos
assertValue("anyo", getAnyoActual());
assertValue("numero", getNumero());
assertValue("fecha", getFechaActual());
assertValue("cliente.numero", "1");
assertValue("cliente.nombre", "JAVIER PANIZA");
assertCollectionRowCount("detalles", 2);
// Fila 0
assertValueInCollection("detalles", 0, "producto.numero", "1");
assertValueInCollection("detalles", 0, "producto.descripcion",
"Peopleware: Productive Projects and Teams");
assertValueInCollection("detalles", 0, "cantidad", "2");
// Fila 1
assertValueInCollection("detalles", 1, "producto.numero", "2");
assertValueInCollection("detalles", 1, "producto.descripcion",
"Arco iris de lágrimas");
assertValueInCollection("detalles", 1, "cantidad", "1");
assertValue("observaciones", "Esto es una prueba JUNIT");
}
private void borrar() throws Exception {
execute("CRUD.delete");
assertNoErrors();
}
El código de prueba hasta aquí es para aplicar sobre el código de la lección 5. Aquí puedes descarga el código fuente de la lección 5 pero incluyendo el código de prueba de arriba:
Descarga el código fuente hasta la lección 5 con pruebas
Todo el código a descargar a partir de la lección 5 ya include el código de prueba, que puedes ver con explicaciones a partir de aquí.
package com.tuempresa.facturacion.pruebas;
import java.time.*;
import java.time.format.*;
import javax.persistence.*;
import org.openxava.tests.*;
import static org.openxava.jpa.XPersistence.*;
abstract public class PruebaDocumentoComercial // Añade abstract a la definición de clase
extends ModuleTestBase {
private String numero;
public PruebaDocumentoComercial(
String nombrePrueba,
String nombreModulo) // nombreModulo añadido como argumento en el constructor
{
super(nombrePrueba, "facturacion", nombreModulo); // nombreModulo en vez de "Factura"
}
public void testCrear() throws Exception { … } // Como el original
private void anyadirDetalles() throws Exception { … } // Como el original
private String getNumero() {
if (numero == null) {
Query query = getManager().
createQuery(
"select max(f.numero) "
+ "from DocumentoComercial f " // Factura cambiada por DocumentoComercial
+ "where f.anyo = :anyo");
query.setParameter("anyo", LocalDate.now().getYear());
Integer ultimoNumero = (Integer) query.getSingleResult();
if (ultimoNumero == null) ultimoNumero = 0;
numero = Integer.toString(ultimoNumero + 1);
}
return numero;
}
private void borrar() throws Exception { … } // Como original
private void verificarCreado() throws Exception { … } // Como original
private void grabar() throws Exception { … } // Como original
private void ponerOtrasPropiedades() throws Exception { … } // Como original
private void escogerCliente() throws Exception { … } // Como original
private void verificarValoresDefecto() throws Exception { … } // Como original
private String getAnyoActual() { … } // Como original
private String getFechaActual() { … } // Como original
}
Como ves has tenido que hacer unos pocos cambios para adaptar PruebaDocumentoComercial. Primero, la has declarado abstracta, de esta forma esta clase no es ejecutada por OpenXava Studio como una prueba JUnit, es solo válida como clase base para crear pruebas, pero ella misma no es una prueba.package com.tuempresa.facturacion.pruebas;
public class PruebaFactura extends PruebaDocumentoComercial {
public PruebaFactura(String nombrePrueba) {
super(nombrePrueba, "Factura");
}
}
Y PruebaPedido:package com.tuempresa.facturacion.pruebas;
public class PruebaPedido extends PruebaDocumentoComercial {
public PruebaPedido(String nombrePrueba) {
super(nombrePrueba, "Pedido");
}
}
Ejecuta estas dos prueba y verás como testCrear(), heredado de PruebaDocumentoComercial, se ejecuta en ambos casos, contra su módulo correspondiente. Con esto estamos probando el comportamiento común para Pedido y Factura. Probemos ahora la funcionalidad particular de cada uno.// Esta prueba confía en que al menos exista una factura y un pedido
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty(); // Esta prueba confía en que ya existen facturas
execute("List.orderBy", "property=numero"); // Para usar siempre el mismo pedido
execute("List.viewDetail", "row=0"); // Va al modo detalle editando la primera factura
execute("Sections.change", "activeSection=1"); // Cambia a la pestaña 1
assertCollectionRowCount("pedidos", 0); // Esta factura no tiene pedidos
execute("Collection.add", // Pulsa el botón para añadir un nuevo pedido, esto te lleva
"viewObject=xava_view_section1_pedidos"); // a la lista de pedidos
execute("AddToCollection.add", "row=0"); // Escoge el primer pedido de la lista
assertCollectionRowCount("pedidos", 1); // El pedido se ha añadido a la factura
checkRowCollection("pedidos", 0); // Marca el pedido, para borrarlo
execute("Collection.removeSelected", // Borra el pedido recién añadido
"viewObject=xava_view_section1_pedidos");
assertCollectionRowCount("pedidos", 0); // El pedido ha sido borrado
}
En este caso asumimos que hay al menos una factura y que la primera factura de la lista no tiene pedidos. Antes de ejecutar esta prueba, si no tienes facturas todavía, crea una sin pedidos, o si ya tienes facturas, asegúrate de que la primera no tiene pedidos.public void testPonerFactura() throws Exception {
login("admin", "admin");
assertListNotEmpty(); // Esta prueba confía en que existen pedidos
execute("List.viewDetail", "row=0"); // Va a modo detalle editando la primera factura
execute("Sections.change", "activeSection=1"); // Cambia a la pestaña 1
assertValue("factura.numero", ""); // Este pedido todavía no tiene
assertValue("factura.anyo", ""); // una factura asignada
execute("Reference.search", // Pulsa en el botón para buscar la factura, esto te
"keyProperty=factura.anyo"); // lleva a la lista de facturas
String anyo = getValueInList(0, "anyo"); // Memoriza el año y el número de
String numero = getValueInList(0, "numero"); // la primera factura de la lista
execute("ReferenceSearch.choose", "row=0"); // Escoge la primera factura
assertValue("factura.anyo", anyo); // Al volver al detalle del pedido verificamos
assertValue("factura.numero", numero); // que la factura ha sido seleccionada
}
En este caso asumimos que hay al menos un pedido y el primer pedido de la lista no tiene factura. Antes de ejecutar esta prueba, si no tienes pedidos, crea uno sin factura, o si ya tienes pedidos, asegúrate de que el primero no tiene factura.public void testCrear() throws Exception {
login("admin", "admin");
calcularNumero(); // Añadido para calcular primero el siguiente número de documento
verificarValoresDefecto();
escogerCliente();
anyadirDetalles();
ponerOtrasPropiedades();
grabar();
verificarBeneficioEstimado(); // Prueba @Formula
verificarCreado();
borrar();
}
Como ves, añadimos una nueva línea, después de login(...), para calcular el siguiente número de documento, y una llamada al nuevo método verificarBeneficioEstimado().private void calcularNumero() {
Query query = getManager().createQuery(
"select max(f.numero) from " +
modelo + // Cambiamos DocumentoComercial por una variable
" f where f.anyo = :anyo");
query.setParameter("anyo", LocalDate.now().getYear());
Integer ultimoNumero = (Integer) query.getSingleResult();
if (ultimoNumero == null) ultimoNumero = 0;
numero = Integer.toString(ultimoNumero + 1);
}
private String getNumero() {
return numero;
}
Anteriormente, teníamos solo getNumero() que calculaba y devolvía el número, ahora tenemos un método para calcular (calcularNumero()), y otro para devolver el resultado (getNumero()). Puedes notar que la lógica del cálculo tiene un pequeño cambio, en vez de usar “DocumentoComercial” como fuente de la consulta usamos modelo, una variable. Esto es así porque ahora la numeración para facturas y pedidos está separada. Llenamos esta variable, un campo de la clase de prueba, en el constructor, tal como muestra el siguiente código:private String modelo; // Nombre del modelo para la condición. Puede ser 'Factura' o 'Pedido'
public PruebaDocumentoComercial(String nombrePrueba, String nombreModulo) {
super(nombrePrueba, "facturacion", nombreModulo);
this.modelo = nombreModulo; // El nombre del módulo coincide con el del modelo
}
En este caso el nombre de módulo, Factura o Pedido, coincide con el nombre de modelo, Factura o Pedido, así que la forma más fácil de obtener el nombre de modelo es desde el nombre de módulo.private void verificarValoresDefecto() throws Exception {
execute("CRUD.new");
assertValue("anyo", getAnyoActual());
// assertValue("numero", getNumero()); // Ahora el número no tiene valor inicial...
assertValue("numero", ""); // ... al crear un documento nuevo
assertValue("fecha", getFechaActual());
}
Verificamos que numero no tiene valor inicial, porque ahora numero no se calcula hasta el momento de grabar el documento (sección Cálculo de valor por defecto multiusuario). Cuando el documento (factura o pedido) se grabe verificaremos que numero se calcula.
private void anyadirDetalles() throws Exception {
assertCollectionRowCount("detalles", 0);
// Antes de ejecutar esta prueba asegurate de que
// producto 1 tenga 19 como precio y
// producto 2 tenga 20 como precio
// Añadir una línea de detalle
setValueInCollection("detalles", 0, "producto.numero", "1");
assertValueInCollection("detalles", 0,
"producto.descripcion", "Peopleware: Productive Projects and Teams");
assertValueInCollection("detalles", 0,
"precioPorUnidad", "19,00"); // @DefaultValueCalculator
setValueInCollection("detalles", 0, "cantidad", "2");
assertValueInCollection("detalles", 0,
"importe", "38,00"); // Propiedada calculada, sección 'Propiedad calculada simple'
// Verificando propiedades de total de la colección
assertTotalInCollection("detalles", 0, "importe", "38,00"); // Suma de importes usando +
assertTotalInCollection("detalles", 1, "importe", "21"); // Valor por defecto desde un archivo de propiedades
assertTotalInCollection("detalles", 2, "importe", "7,98"); // IVA, con @Calculation
assertTotalInCollection("detalles", 3, "importe", "45,98"); // Importe total, con @Calculation
// Añadir otro detalle
setValueInCollection("detalles", 1, "producto.numero", "2");
assertValueInCollection("detalles", 1, "producto.descripcion", "Arco iris de lágrimas");
assertValueInCollection("detalles", 1, "precioPorUnidad", "20,00");
setValueInCollection("detalles", 1, "precioPorUnidad", "10,00"); // Modificando el valor por defecto
setValueInCollection("detalles", 1, "cantidad", "1");
assertValueInCollection("detalles", 1, "importe", "10,00");
assertCollectionRowCount("detalles", 2); // Ahora tenemos dos líneas
// Verificando propiedades de total de la colección
assertTotalInCollection("detalles", 0, "importe", "48,00");
assertTotalInCollection("detalles", 1, "importe", "21");
assertTotalInCollection("detalles", 2, "importe", "10,08");
assertTotalInCollection("detalles", 3, "importe", "58,08");
}
Como ves, con estas modificaciones sencillas probamos la mayoría de nuestro nuevo código. Nos quedan sólo las propiedades beneficioEstimado y diasEntrega. Las cuales probaremos en las siguientes secciones.private void verificarBeneficioEstimado() throws Exception {
execute("Mode.list"); // Cambiar a modo lista
setConditionValues(new String [] { // Filtra para ver en la lista solamente
getAnyoActual(), getNumero() // el documento que acabamos de crear
});
execute("List.filter"); // Hace filtro
assertValueInList(0, 0, getAnyoActual()); // Verifica que
assertValueInList(0, 1, getNumero()); // el filtro ha funcionado
assertValueInList(0, "beneficioEstimado", "5,81"); // Confirma el beneficio estimado
execute("List.viewDetail", "row=0"); // Va a modo detalle
}
Dado que ahora vamos a modo lista y después volvemos a detalles, hemos de hacer una pequeña modificación en el método verificarCreado(), que es ejecutado justo después de verificarBeneficioEstimado(). Veamos la modificación:private void verificarCreado() throws Exception {
// setValue("anyo", getAnyoActual()); // Borramos estas líneas
// setValue("numero", getNumero()); // para buscar el documento
// execute("CRUD.refresh"); // porque ya lo hemos buscado desde el modo lista
// El resto de la prueba ...
...
Quitamos estas líneas porque ahora no es necesario buscar el documento recién creado. Ahora en el método verificarBeneficioEstimado() vamos a modo lista y escogemos el documento, por tanto ya estamos editando el documento.public void testDiasEntrega() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.viewDetail", "row=0");
setValue("fecha", "5/6/2020");
assertValue("diasEntregaEstimados", "1");
setValue("fecha", "6/6/2020");
assertValue("diasEntregaEstimados", "3");
setValue("fecha", "7/6/2020");
assertValue("diasEntregaEstimados", "2");
execute("CRUD.save");
execute("Mode.list"); // Para verificar que diasEntrega está sincronizado
assertValueInList(0, "diasEntrega", "2");
execute("List.viewDetail", "row=0");
setValue("fecha", "13/1/2020");
assertValue("diasEntregaEstimados", "7");
execute("CRUD.save");
execute("Mode.list"); // Para verificar que diasEntrega está sincronizado
assertValueInList(0, "diasEntrega", "7");
}
Probamos varios valores para fecha para verificar que diasEntregaEstimados se calcula correctamente cada vez, además vamos a modo lista para verificar que diasEntrega tiene el valor correcto y por tanto ambas propiedades están sincronizadas.
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero");
execute("List.viewDetail", "row=0");
execute("Sections.change", "activeSection=1");
assertCollectionRowCount("pedidos", 0);
execute("Collection.add",
"viewObject=xava_view_section1_pedidos");
// execute("AddToCollection.add", "row=0"); // Ahora no seleccionamos al azar
seleccionarPrimerPedidoConEntregadoIgual("Entregado"); // Selecciona un pedido entregado
seleccionarPrimerPedidoConEntregadoIgual(""); // Selecciona uno no entregado
execute("AddToCollection.add"); // Tratamos de añadir ambos
assertError( // Un error, porque el pedido no entregado no se puede añadir
"¡ERROR! 1 elemento(s) NO añadido(s) a Pedidos de Factura");
assertMessage( // Un mensaje de confirmación, porque el pedido entregado ha sido añadido
"1 elemento(s) añadido(s) a Pedidos de Factura");
assertCollectionRowCount("pedidos", 1);
checkRowCollection("pedidos", 0);
execute("Collection.removeSelected",
"viewObject=xava_view_section1_pedidos");
assertCollectionRowCount("pedidos", 0);
}
Hemos modificado la parte de la selección de pedidos a añadir, antes seleccionábamos el primero, no importaba si estaba servido o no. Ahora seleccionamos un pedido servido y otro no servido, de esta forma comprobamos que el pedido servido se añade y el no servido es rechazado.private void seleccionarPrimerPedidoConEntregadoIgual(String valor) throws Exception {
int c = getListRowCount(); // El total de filas visualizadas en la lista
for (int i = 0; i < c; i++) {
if (valor.equals(getValueInList(i, 12))) { // Obtenermos valor de la columna 'entregado'
checkRow(i);
return;
}
}
fail("Debe tener al menos una fila con entregado=" + valor);
}
Aquí ves una buena técnica para hacer un bucle sobre los elementos visualizados de una lista para seleccionarlos y coger algunos datos, o cualquier otra cosa que quieras hacer con los datos de la lista. Para que esta prueba funcione la primera factura no ha de tener pedidos y además tiene que haber al menos un pedido entregado, pero que no sea el primero.public void testPonerFactura() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero"); // Establece el orden de la lista
execute("List.viewDetail", "row=0");
assertValue("entregado", "false"); // El pedido no debe estar entregado
execute("Sections.change", "activeSection=1");
assertValue("factura.numero", "");
assertValue("factura.anyo", "");
execute("Reference.search",
"keyProperty=factura.anyo");
String anyo = getValueInList(0, "anyo");
String numero = getValueInList(0, "numero");
execute("ReferenceSearch.choose", "row=0");
assertValue("factura.anyo", anyo);
assertValue("factura.numero", numero);
// Los pedidos no entregados no pueden tener factura
execute("CRUD.save");
assertErrorsCount(1); // No podemos grabar porque no ha sido entregado
setValue("entregado", "true");
execute("CRUD.save"); // Con 'entregado=true' podemos grabar el pedido
assertNoErrors();
// Un pedido con factura no se puede borrar
execute("Mode.list"); // Vamos al modo lista
execute("CRUD.deleteRow", "row=0"); // y eliminanos el pedido grabado
assertError("Imposible borrar Pedido por: " + // No podemos borrar porque tiene
"Pedido asociado a factura no puede ser eliminado"); // una factura asociada
// Restaurar los valores originales
execute("List.viewDetail", "row=0");
setValue("factura.anyo", "");
setValue("entregado", "false");
execute("CRUD.save");
assertNoErrors();
}
La prueba original solo buscaba una factura, ni siquiera intentaba grabar. Ahora, hemos añadido código al final para probar la grabación de un pedido marcado como servido y marcado como no servido, de esta forma comprobamos la validación. Después de eso, tratamos de borrar el pedido, el cual tiene una factura, así probamos también la validación al borrar. Antes de ejecutar esta prueba asegurate de que el primer pedido no esté entregado y no tenga factura.public void testValidarISBN() throws Exception {
login("admin", "admin");
// Buscar producto1
execute("CRUD.new");
setValue("numero", Integer.toString(producto1.getNumero()));
execute("CRUD.refresh");
assertValue("descripcion", "Producto JUNIT 1");
assertValue("isbn", "");
// Con un formato de ISBN incorrecto
setValue("isbn", "1111");
execute("CRUD.save"); // Falla por el formato (apache commons validator)
assertError("1111 no es un valor válido para ISBN de Producto: " +
"ISBN inválido o inexistente");
// ISBN no existe aunque tiene un formato correcto
setValue("isbn", "9791034369997");
execute("CRUD.save"); // Falla porque no existe ISBN (el servicio REST)
assertError("9791034369997 no es un valor válido para ISBN de " +
"Producto: ISBN inválido o inexistente");
// ISBN existe
setValue("isbn", "9780932633439");
execute("CRUD.save"); // No falla
assertNoErrors();
}
Seguramente la prueba manual que hacías mientras estabas escribiendo el validador @ISBN era parecida a esta. Por eso, si hubieras escrito tu código de prueba antes que el código de la aplicación, lo hubieras podido usar mientras que desarrollabas, lo cual es más eficiente que repetir una y otra vez a mano las pruebas con el navegador.// En el archivo PruebaCliente.java
public class PruebaCliente extends ModuleTestBase {
...
public void testCrearLeerActualizarBorrar() throws Exception {
...
// Borrar
// execute("CRUD.delete");
execute("Facturacion.delete");
assertMessage("Cliente borrado satisfactoriamente");
}
...
}
// En el archivo PruebaDocumentoComercial.java
abstract public class PruebaDocumentoComercial extends ModuleTestBase {
...
private void borrar() throws Exception {
// execute("CRUD.delete");
execute("Facturacion.delete");
assertNoErrors();
}
...
}
// En el archivo PruebaProducto.java
public class PruebaProducto extends ModuleTestBase {
...
public void testBorrarDesdeLista() throws Exception {
//execute("CRUD.deleteSelected");
execute("Facturacion.deleteSelected");
assertListRowCount(1);
}
...
}
// En el archivo PruebaPedido.java
public class PruebaPedido extends PruebaDocumentoComercial {
...
public void testPonerFactura() throws Exception {
...
//execute("CRUD.deleteRow", "row=0");
execute("Facturacion.deleteRow", "row=0");
...
}
}
Después de estos cambios todas tus prueba funcionarán bien y esto confirma que tus acciones para borrar personalizadas conservan la semántica original. Solo ha cambiado la implementación.public void testPapelera() throws Exception {
login("admin", "admin");
confirmarSoloUnaPaginaEnLista(); // Sólo una página en la lista, es decir menos de 10 filas
// Borrar desde modo detalle
int numeroFilasInicial = getListRowCount();
String anyo1 = getValueInList(0, 0);
String numero1 = getValueInList(0, 1);
execute("List.viewDetail", "row=0");
execute("Facturacion.delete");
execute("Mode.list");
assertListRowCount(numeroFilasInicial - 1); // Hay una fila menos
confirmarDocumentoNoEstaEnLista(anyo1, numero1); // La entidad borrada no está en lista
// Borrar desde el modo lista
String anyo2 = getValueInList(0, 0);
String numero2 = getValueInList(0, 1);
checkRow(0);
execute("Facturacion.deleteSelected");
assertListRowCount(numeroFilasInicial - 2); // Hay dos filas menos
confirmarDocumentoNoEstaEnLista(anyo2, numero2); // La otra entidad borrada no está en la lista
// Verificar la entidades borradas en el módulo papelera
changeModule("Papelera" + modelo); // model puede ser 'Factura' o 'Pedido'
confirmarSoloUnaPaginaEnLista();
int numeroFilasInicialPapelera = getListRowCount();
confirmarDocumentoEstaEnLista(anyo1, numero1); // Verificamos que las entidades borradas
confirmarDocumentoEstaEnLista(anyo2, numero2); // están en la lista del módulo papelera
// Restaurar usando una acción de fila
int fila1 = getFilaDocumentoEnLista(anyo1, numero1);
execute("Papelera.restaurar", "row=" + fila1);
assertListRowCount(numeroFilasInicialPapelera - 1); // 1 fila menos después de restaurar
confirmarDocumentoNoEstaEnLista(anyo1, numero1); // La entidad restaurada ya
// no se muestra en la lista del módulo papelera
// Restaurar seleccionando una fila y usando el botón de abajo
int fila2 = getFilaDocumentoEnLista(anyo2, numero2);
checkRow(fila2);
execute("Papelera.restaurar");
assertListRowCount(numeroFilasInicialPapelera - 2); // 2 filas menos
confirmarDocumentoNoEstaEnLista(anyo2, numero2); // La entidad restaurada ya
// no se muestra en la lista del módulo papelera
// Verificar las entidades restauradas
changeModule(modelo);
assertListRowCount(numeroFilasInicial); // Después de restaurar tenemos
confirmarDocumentoEstaEnLista(anyo1, numero1); // las filas originales de nuevo
confirmarDocumentoEstaEnLista(anyo2, numero2);
}
Como ves testPapelera() sigue los susodichos pasos. Fíjate como usando el método changeModule() de ModuleTestBase tu prueba puede cambiar a otro módulo. Usamos esto para cambiar al módulo papelera y volver atrás.private void confirmarSoloUnaPaginaEnLista() throws Exception {
assertListNotEmpty(); // De ModuleTestBase
assertTrue("Debe tener menos de 10 filas para ejecutar esta prueba",
getListRowCount() < 10);
}
Necesitamos tener menos de 10 filas, porque el método getListRowCount() informa solo de las filas visualizadas, por tanto si tienes más de 10 filas (10 es el número de filas por página por defecto) no puedes aprovechar getListRowCount(), ya que siempre devolvería 10.private void confirmarDocumentoNoEstaEnLista(String anyo, String numero)
throws Exception
{
assertTrue(
"Documento " + anyo + "/" + numero + " no debe estar en la lista",
getFilaDocumentoEnLista(anyo, numero) < 0);
}
private void confirmarDocumentoEstaEnLista(String anyo, String numero)
throws Exception
{
assertTrue(
"Documento " + anyo + "/" + numero + " debe estar en la lista",
getFilaDocumentoEnLista(anyo, numero) >= 0);
}
private int getFilaDocumentoEnLista(String anyo, String numero)
throws Exception
{
int c = getListRowCount();
for (int i = 0; i < c; i++) {
if (anyo.equals(getValueInList(i, 0)) &&
numero.equals(getValueInList(i, 1)))
{
return i;
}
}
return -1;
}
Puedes ver en getFilaDocumentoEnLista() como se hace un bucle para buscar valores concretos en una lista.public void testCrearFacturaDesdePedido() throws Exception {
login("admin", "admin");
// Buscar el pedido
buscarPedidoSusceptibleDeSerFacturado(); // Busca un pedido
assertValue("entregado", "true"); // El pedido está entregado
int cantidadDetallesPedido = getCollectionRowCount("detalles"); // Toma nota de
// la cantidad de detalles en el pedido
execute("Sections.change", "activeSection=1"); // La sección de la factura
assertValue("factura.anyo", ""); // Todavía no hay factura
assertValue("factura.numero", ""); // en este pedido
// Crear la factura
execute("Pedido.crearFactura"); // Ejecuta la acción que estamos probando (1)
String anyoFactura = getValue("factura.anyo"); // Verifica que ahora
assertTrue("Año de fectura ha de tener valor", // hay una factura
!Is.emptyString(anyoFactura)); // en la pestaña de factura (2)
String numeroFactura = getValue("factura.numero");
assertTrue("Número de factura ha de tener valor",
!Is.emptyString(numeroFactura)); // Is.emptyString() es de org.openxava.util
assertMessage("Factura " + anyoFactura + "/" + numeroFactura +
" creada a partir del pedido actual"); // El mensaje de confirmación (3)
assertCollectionRowCount("factura.detalles", // La factura recién creada
cantidadDetallesPedido); // tiene el mismo número de detalles que el pedido (4)
// Restaurar el pedido para poder ejecutar la prueba la siguiente vez
setValue("factura.anyo", "");
assertValue("factura.numero", "");
assertCollectionRowCount("factura.detalles", 0);
execute("CRUD.save");
assertNoErrors();
}
Esta prueba pulsa el botón para ejecutar la acción Pedido.crearFactura (1), entonces verifica que una factura ha sido creada, está siendo visualizada en la pestaña de factura (2) y tiene la misma cantidad de líneas de detalle que el pedido actual (4). También comprueba que se ha generado el mensaje de confirmación correcto (3).private void buscarPedidoSusceptibleDeSerFacturado() throws Exception {
buscarPedidoUsandoLista("entregado = true and factura = null"); // Envía la condición,
} // en este caso buscamos por un pedido entregado y sin factura
private void buscarPedidoUsandoLista(String condicion) throws Exception {
Pedido pedido = buscarPedido(condicion); // Busca el pedido con la condición usando JPA
String anyo = String.valueOf(pedido.getAnyo());
String numero = String.valueOf(pedido.getNumero());
setConditionValues(new String [] { anyo, numero }); // Llena el año y el número
execute("List.filter"); // y pulsa en el botón filtrar en la lista
assertListRowCount(1); // Sólo una fila, correspondiente al pedido buscado
execute("List.viewDetail", "row=0"); // Para ver el pedido en modo detalle
assertValue("anyo", anyo); // Verifica que el pedido editado
assertValue("numero", numero); // es el deseado
}
private Pedido buscarPedido(String condicion) {
Query query = XPersistence.getManager().createQuery( // Crea una consulta JPA
"from Pedido p where p.eliminado = false and " // a partir de la condición. Fíjate en
+ condicion); // deleted = false para excluir los pedidos borrados
List<Pedido> pedidos = query.getResultList();
if (pedidos.isEmpty()) { // Es necesario al menos un pedido con la condición
fail("Para ejecutar esta prueba necesitas tener al menos un pedido con " + condicion);
}
return pedidos.get(0);
}
Además necesitas añadir los siguiente imports a PruebaPedido para que te compile:
import java.util.*;
import javax.persistence.*;
import org.openxava.jpa.*;
import org.openxava.util.*;
import com.tuempresa.facturacion.modelo.*;
El método buscarPedidoSusceptibleDeSerFacturado() simplemente llama a un método más genérico, buscarPedidoUsandoLista(), para buscar una entidad por una condición. El método buscarPedidoUsandoLista() obtiene la entidad Pedido mediante buscarPedido(), entonces usa la lista para filtrar por el año y el número a partir de este Pedido, yendo a modo detalle al finalizar. El método buscarPedido() usa JPA simple y llano para buscar.public void testOcultaCrearFacturaDesdePedidoCuandoNoAplicable() throws Exception {
login("admin", "admin");
buscarPedidoUsandoLista(
"entregado = true and factura <> null"); // Si el pedido ya tiene factura
assertNoAction("Pedido.crearFactura"); // no se puede facturar otra vez
execute("Mode.list");
buscarPedidoUsandoLista(
"entregado = false and factura = null"); // Si el pedido no está entregado
assertNoAction("Pedido.crearFactura"); // no se puede facturar
execute("CRUD.new"); // Si el pedido todavía no está grabado
assertNoAction("Pedido.crearFactura"); // no puede ser facturado
}
Probamos tres casos en los que el botón para crear la factura no tiene que estar presente. Fíjate en el uso de assertNoAction() para preguntar si el vínculo o botón para una acción está presente en la interfaz de usuario. Aquí estamos reutilizando el método buscarPedidoUsandoLista() desarrollado en la sección anterior.public void testCrearFacturaDesdePedidosSeleccionados() throws Exception {
login("admin", "admin");
verificarPedido(2021, 2, 1, "45.98"); // El pedido 2021/2 tiene 1 línea y 45,98 de importe base
verificarPedido(2021, 4, 2, "98.01"); // El pedido 2021/4 tiene 2 líneas y 98,01 de importe base
execute("List.orderBy", "property=numero"); // Ordena la lista por número
checkRow( // Marca la fila a partir del número de fila
getFilaDocumentoEnLista("2021", "2") // Obtiene la fila del año y número del pedido
); // por tanto, esta línea marca la línea del pedido 2021/2 en la lista (1)
checkRow(
getFilaDocumentoEnLista("2021", "4") // Marca el pedido 2021/4 en la lista (1)
);
execute("Pedido.crearFacturaDesdePedidosSeleccionados"); // Ejecuta la acción que
// estamos probando (2)
String anyoFactura = getValue("anyo"); // Ahora estamos viendo el detalle de
String numeroFactura = getValue("numero"); // la factura recién creada
assertMessage("Factura " + anyoFactura + "/" + numeroFactura +
" creada a partir de los pedidos: [2021/2, 2021/4]"); // El mensaje de confirmación
assertCollectionRowCount("detalles", 3); // Confirma que el número de líneas de la
// factura recién creada es la suma de la de los pedidos fuente (3)
assertValue("importeTotal", "143,99"); // Confirma que el importe base de la factura
// recién creada es la suma de la de los pedidos fuente (4)
execute("Sections.change", "activeSection=1"); // Cambia a la pestaña de
// pedidos de la factura
assertCollectionRowCount("pedidos", 2); // La nueva factura tiene 2 pedidos (5)
assertValueInCollection("pedidos", 0, 0, "2021"); // y son los correctos
assertValueInCollection("pedidos", 0, 1, "2");
assertValueInCollection("pedidos", 1, 0, "2021");
assertValueInCollection("pedidos", 1, 1, "4");
assertAction("EdicionFactura.grabar"); // Los botones GRABAR (6)
assertAction("EdicionFactura.cerrar"); // y CERRAR (6)
checkRowCollection("pedidos", 0); // Seleccionamos los 2 pedidos
checkRowCollection("pedidos", 1);
execute("Collection.removeSelected", // y los borramos, para ejecutar esta prueba
"viewObject=xava_view_section1_pedidos"); // otra vez usando los mismo pedidos
assertNoErrors();
execute("EdicionFactura.cerrar"); // Vuelve a la lista de pedidos (7)
confirmarDocumentoEstaEnLista("2021", "2"); // Confirma que estamos realmente
confirmarDocumentoEstaEnLista("2021", "4"); // en la lista de pedidos
}
Esta prueba marca dos pedidos (1) y pulsa en el botón CREAR FACTURA DESDE LOS PEDIDOS SELECCIONADOS (2). Entonces verifica que se ha creado una nueva factura con el número correcto de líneas (3), importe total (4) y lista de pedidos (5). También verifica que las acciones GRABAR y CERRAR están disponibles (6) y usa el botón CERRAR para volver a la lista de pedidos (7).protected void confirmarDocumentoEstaEnLista(String anyo, String numero) ... // protected en lugar
// private void confirmarDocumentoEstaEnLista(String anyo, String numero) ... // de private
protected int getFilaDocumentoEnLista(String anyo, String numero) ... // protected en lugar
// private int getFilaDocumentoEnLista(String anyo, String numero) ... // de private
El único detalle pendiente es el método verificarPedido() que veremos en la siguiente sección.
private void verificarPedido(
int anyo, int numero, int cantidadDetalles, String importeTotal)
{
Pedido pedido = buscarPedido("anyo = " + anyo + " and numero=" + numero);
assertEquals("Para ejecutar esta prueba el pedido " +
pedido + " tiene que tener " + cantidadDetalles + " detalles",
cantidadDetalles, pedido.getDetalles().size());
assertTrue("Para ejecutar esta prueba el pedido " +
pedido + " must have " + importeTotal + " como importe total",
pedido.getImporteTotal().compareTo(new BigDecimal(importeTotal)) == 0);
assertTrue("Para ejecutar esta prueba el pedido " + pedido + " tiene que estar entegrado",
pedido.isEntregado());
}
Este método busca un pedido y verifica la cantidad de líneas, el importe total y si el pedido está entregado. Usar este método tiene la ventaja de que si los pedidos necesarios para la prueba no están en la base de datos con los valores correctos obtienes un mensaje preciso. Así, no derrocharás tu tiempo intentando adivinar que es lo que está mal. Esto es especialmente útil si la prueba no la está ejecutando el programador original. Por cierto, si te resulta dificil adaptar tus pedidos para que se ajusten a esta prueba (número de pedido, importe, número de líneas), puedes adaptar los valores en la prueba a tus pedidos actuales.public void testExcepcionesCreandoFacturaDesdePedido() throws Exception {
login("admin", "admin");
confirmarExcepcionCreandoFacturaDesdePedido( // Confirma que cuando el pedido ya tiene (1)
"entregado = true and factura <> null", // factura se produce el error correcto
"Ha sido imposible ejecutar la acción Crear factura desde pedidos seleccionados: " +
"El pedido ya tiene una factura"
);
confirmarExcepcionCreandoFacturaDesdePedido( // Confirma que cuando el pedido no está (2)
"entregado = false and factura = null", // entregado se produce el error correcto
"Ha sido imposible ejecutar la acción Crear factura desde pedidos seleccionados: " +
"El pedido todavía no está entregado"
);
}
private void confirmarExcepcionCreandoFacturaDesdePedido(
String condicion, String mensaje) throws Exception
{
Pedido pedido = buscarPedido(condicion); // Busca el pedido por la condición (3)
int fila = getFilaDocumentoEnLista( // y obtiene el número de fila para ese pedido (4)
String.valueOf(pedido.getAnyo()),
String.valueOf(pedido.getNumero())
);
checkRow(fila); // Marca la fila (5)
execute("Pedido.crearFacturaDesdePedidosSeleccionados"); // Trata de crear la factura (6)
assertError(mensaje); // ¿Se ha mostrado el mensaje esperado? (7)
uncheckRow(fila); // Desmarca la fila, así podemos llamar a este método otra vez
}
La prueba verifica que el mensaje es el correcto cuando tratamos de crear una factura a partir de un pedido que ya tiene factura (1), y también desde un pedido no entregado todavía (2). Para hacer estas verificaciones llama al método confirmarExcepcionCreandoFacturaDesdePedido(). Este método busca la entidad Pedido usando la condición (3), localiza la fila donde la entidad se está visualizando (4) y la marca (5). Después, la prueba ejecuta la acción (6) y verifica que el mensaje esperado se muestra (7).public void testPonerFactura() throws Exception {
...
assertValue("factura.numero", "");
assertValue("factura.anyo", "");
// execute("Reference.search", // Ya no usamos la acción estándar para
// "keyProperty=factura.anyo"); // buscar la factura, en su lugar
execute("Pedido.buscarFactura", // usamos nuestra acción personalizada (1)
"keyProperty=factura.numero");
execute("List.orderBy", "property=numero");
...
// Restaurar valores
setValue("factura.anyo", ""); // Ahora es necesario teclear el año
setValue("factura.numero", ""); // y el número para buscar la factura (2)
setValue("entregado", "false");
execute("CRUD.save");
assertNoErrors();
}
Recuerda que anotamos la referencia factura en Pedido con @SearchAction("Pedido.buscarFactura"), por tanto hemos de modificar la prueba para llamar a Pedido.buscarFactura (1) en vez de a Reference.search. También añadimos @SearchKey a anyo y numero de CommercialDocument, por lo tanto nuestra prueba ha de indicar anyo tanto como numero para obtener (o en este caso borrar) una factura (2). Por causa de esto último también hemos de modificar testCrearFacturaDesdePedido() de PruebaPedido como se muestra:
public void testCrearFacturaDesdePedido() throws Exception {
...
// Restaurar el pedido para ejecutar la prueba la siguiente vez
setValue("factura.anyo", ""); // Ahora es necesario teclear el año
setValue("factura.numero", ""); // y el número para buscar la factura (2)
assertValue("factura.numero", "");
assertCollectionRowCount("factura.detalles", 0);
execute("CRUD.save");
assertNoErrors();
}
Después de estos cambios PruebaPedido tiene que pasar. Sin embargo, todavía nos queda probar la nueva funcionalidad del módulo Pedido.
public void testBuscarFacturaDesdePedido() throws Exception {
login("admin", "admin");
execute("CRUD.new");
setValue("cliente.numero", "1"); // Si el cliente es 1...
execute("Sections.change", "activeSection=1");
execute("Pedido.buscarFactura", // ...cuando el usuario pulsa para escoger una factura...
"keyProperty=factura.numero");
confirmarClienteEnTodasFilas("1"); // ...sólo se muestran las facturas del cliente 1
execute("ReferenceSearch.cancel");
execute("Sections.change", "activeSection=0");
setValue("cliente.numero", "2"); // Y si el cliente es 2...
execute("Sections.change", "activeSection=1");
execute("Pedido.buscarFactura", // ...cuando el usuario pulsa para escoger una factura...
"keyProperty=factura.numero");
confirmarClienteEnTodasFilas("2"); // ...sólo se muestran las facturas del cliente 2
}
La parte más peliaguda es verificar la lista de facturas, este es el trabajo confirmarClienteEnTodasFilas() en PruebaPedido:private void confirmarClienteEnTodasFilas(String numeroCliente) throws Exception {
assertListNotEmpty();
int c = getListRowCount();
for (int i=0; i<c; i++) { // Un bucle por todas las filas
if (!numeroCliente.equals(getValueInList(i, "cliente.numero"))) {
fail("Cliente en fila " + i + // Si el cliente no es el esperado falla
" no es " + numeroCliente);
}
}
}
Consiste en un bucle por todas la filas verificando el número de cliente.
public void testAlCambiarFactura() throws Exception {
login("admin", "admin");
execute("CRUD.new"); // Estamos creando un nuevo pedido
assertValue("cliente.numero", ""); // por tanto no tiene cliente todavía
execute("Sections.change", "activeSection=1");
execute("Pedido.buscarFactura", // Busca la factura usando una lista
"keyProperty=factura.numero");
execute("List.orderBy", "property=cliente.numero"); // Ordena por cliente
String numeroCliente1 = getValueInList(0, "cliente.numero"); // Memoriza..
String anyoFactura1 = getValueInList(0, "anyo"); // ...los datos de la...
String numeroFactura1 = getValueInList(0, "numero"); // ...primera factura
execute("List.orderBy", "property=cliente.numero"); // Ordena por cliente
String numeroCliente2 = getValueInList(0, "cliente.numero"); // Memoriza...
String nombreCliente2 = getValueInList(0, "cliente.nombre"); // ...los datos de...
// ...la última factura
assertNotEquals("Han de ser facturas de diferentes clientes",
numeroCliente1, numeroCliente2);// Las 2 facturas memorizadas no son la misma
execute("ReferenceSearch.choose","row=0"); // La factura se escoge con la lista (1)
execute("Sections.change", "activeSection=0");
assertValue("cliente.numero", numeroCliente2); // Los datos del cliente
assertValue("cliente.nombre", nombreCliente2); // se rellenan automáticamente (2)
execute("Sections.change", "activeSection=1");
setValue("factura.anyo", anyoFactura1); // Tratamos de poner una factura de...
setValue("factura.numero", numeroFactura1); // ...otro cliente (3)
assertError("Cliente Nº " + numeroCliente1 + " de la factura " + // Muestra...
anyoFactura1 + "/" + numeroFactura1 + // ...un mensaje de error... (4)
" no coincide con el cliente Nº " +
numeroCliente2 + " del pedido actual");
assertValue("factura.anyo", ""); // ...y reinicia los datos de la factura (5)
assertValue("factura.numero", "");
assertValue("factura.fecha", "");
}
Aquí probamos que nuestra acción @OnChangeSearch rellene los datos del cliente (3) al escoger una factura (2), y que si el cliente ya está establecido se muestre un mensaje de error (4) y la factura se borre de la vista (5). Fíjate como la primera vez usamos la lista (1) para escoger la factura y la segunda lo hacemos tecleando el año y el número (3).
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero");
execute("List.viewDetail", "row=0");
execute("Sections.change", "activeSection=1");
assertCollectionRowCount("pedidos", 0);
// execute("Collection.add", // La acción estándar para añadir pedidos ya no se usa
execute("Factura.anyadirPedidos", // En su lugar usamos nuestra propia acción
"viewObject=xava_view_section1_pedidos");
// seleccionarPrimerPedidoConEntregadoIgual("Entregado"); // Ahora todos los pedidos de la lista
// seleccionarPrimerPedidoConEntregadoIgual(""); // están entregados; esto ya no hace falta
// execute("AddToCollection.add"); // En lugar de la acción estándar
execute("AnyadirPedidosAFactura.add", "row=0"); // ...ahora tenemos la nuestra propia
// assertError("¡ERROR! 1 elemento(s) NO añadido a Pedidos de Factura"); // Es
// imposible porque el usuario no puede escoger pedidos incorrectos
assertMessage("1 elemento(s) añadido a Pedidos de Factura");
assertCollectionRowCount("pedidos", 1);
checkRowCollection("pedidos", 0);
execute("Collection.removeSelected",
"viewObject=xava_view_section1_pedidos");
assertCollectionRowCount("pedidos", 0);
}
Ya no necesitamos el método seleccionarPrimerPedidoConEntregadoIgual(), por tanto podemos quitarlo de PruebaFactura:
// Quita seleccionarPrimerPedidoConEntregadoIgual() de PruebaFactura
// private void seleccionarPrimerPedidoConEntregadoIgual(String valor)
// throws Exception { ... }
Después de estos cambios PruebaFactura ha de funcionar. Sin embargo, todavía nos queda probar la nueva funcionalidad del módulo Factura.
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero");
execute("List.viewDetail", "row=0");
String numeroCliente = getValue("cliente.numero"); // Tomamos nota del
execute("Sections.change", "activeSection=1"); // cliente de la factura
assertCollectionRowCount("pedidos", 0);
execute("Factura.anyadirPedidos",
"viewObject=xava_view_section1_pedidos");
confirmarClienteEnTodasFilas(numeroCliente); // Confirmamos que todos los cliente en
// la lista coinciden con el cliente de la factura
...
}
Ahora hemos de escribir el método confirmarClienteEnTodasFilas(). Pero, espera un momento, ya hemos escrito este método en PruebaPedido. Estamos en PruebaFactura por tanto no podemos llamar a este método. Por fortuna tanto PruebaFactura como PruebaPedido heredan de PruebaDocumentoComercial, por lo tanto sólo tenemos que subir el método a la clase madre. Para hacer esto copia el método confirmarClienteEnTodasFilas() desde PruebaPedido a PruebaDocumentoComercial, cambiando private por protected, tal como se muestra:
abstract public class PruebaDocumentoComercial extends ModuleTestBase {
protected void // Cambiamos de private a protected
confirmarClienteEnTodasFilas(String numeroCliente) throws Exception {
...
}
...
}
Ahora puedes quitar el método confirmarClienteEnTodasFilas() de PruebaPedido:
// Quita confirmarClienteEnTodasFilas() de PruebaPedido
// private void confirmarClienteEnTodasFilas(String numeroCliente)
// throws Exception { ... }
Después de estos cambios el método testAnyadirPedidos() compila y funciona. No solo queremos comprobar que la lista de pedidos son del cliente correcto, sino también que están entregados. Nuestro primer impulso es copiar y pegar confirmarClienteEnTodasFilas() para crear un método confirmarEntregadoEnTodasFilas(). Sin embargo, resistimos la tentación, y en vez de eso vamos a crear un método reutilizable. Primero, copiamos y pegamos confirmarClienteEnTodasFilas() como confirmarValorEnTodasFilas(). Aquí puedes ver estos dos métodos en PruebaDocumentoComercial:
protected void confirmarClienteEnTodasFilas(String numeroCliente) throws Exception {
assertListNotEmpty();
int c = getListRowCount();
for (int i=0; i<c; i++) {
if (!numeroCliente.equals(
getValueInList(i, "cliente.numero"))) // Preguntamos por el cliente de forma fija
{
fail("Cliente en fila " + i +
" no es " + numeroCliente);
}
}
}
protected void confirmarValorEnTodasFilas(int columna, String valor) throws Exception {
assertListNotEmpty();
int c = getListRowCount();
for (int i=0; i<c; i++) {
if (!valor.equals(
getValueInList(i, columna))) // Preguntamos por la columna enviada como parámetro
{
fail("Columna " + columna + " en fila " + i + " no es " + valor);
}
}
}
Puedes ver como con unas ligeras modificaciones hemos convertido en un método genérico para preguntar por el valor de cualquier columna, no solo por la del número de cliente. Ahora hemos de quitar el código redundante, puedes, bien quitar confirmarClienteEnTodasFilas() o bien reimplementarlo usando el nuevo método. El siguiente código en PruebaDocumentoComercial muestra la última opción:protected void confirmarClienteEnTodasFilas(String numeroCliente) throws Exception {
confirmarValorEnTodasFilas(3, numeroCliente); // Número de cliente está en la columna 3
}
Usemos confirmarValorEnTodasFilas() para verificar que la lista de pedidos contiene solo pedidos entregados. El siguiente código muestra la modificación necesaria en testAnyadirPedidos() de PruebaFactura.
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero");
execute("List.viewDetail", "row=0");
String numeroCliente = getValue("cliente.numero");
execute("Sections.change", "activeSection=1");
assertCollectionRowCount("pedidos", 0);
execute("Factura.anyadirPedidos",
"viewObject=xava_view_section1_pedidos");
confirmarClienteEnTodasFilas(numeroCliente);
confirmarValorEnTodasFilas(12, "Entregado"); // Todas las celdas de la columna 12
// tienen 'Entregado'
...
}
Además, queremos que solo los pedidos sin factura se muestren en la lista. Una forma sencilla de hacerlo es verificando que después de añadir un pedido a la factura actual, la lista de pedidos tenga una entrada menos. El siguiente código muestra los cambios necesarios en testAnyadirPedidos() de PruebaFactura para hacer esto:
public void testAnyadirPedidos() throws Exception {
...
confirmarClienteEnTodasFilas(numeroCliente);
confirmarValorEnTodasFilas(12, "Entregado");
int cantidadPedidos = getListRowCount(); // Tomamos nota de la cantidad de pedidos
execute("AnyadirPedidosAFactura.add", "row=0"); // cuando se muestra la lista
assertMessage("1 elemento(s) añadido a Pedidos de Factura");
assertCollectionRowCount("pedidos", 1); // Se añadió un pedido
execute("Factura.anyadirPedidos", // Mostramos la lista de pedidos otra vez
"viewObject=xava_view_section1_pedidos");
assertListRowCount(cantidadPedidos - 1); // Tenemos un pedido menos en la lista
execute("AddToCollection.cancel");
...
}
Con el código de esta sección hemos probado la @AddAction de la colección pedidos, y al mismo tiempo hemos visto como no es necesario crear código genérico desde el principio, porque no es difícil convertir el código concreto en genérico bajo demanda.
public void testAnyadirPedidos() throws Exception {
...
String numeroCliente = getValue("cliente.numero");
assertCollectionRowCount("detalles", 0); // Factura sin detalles para esta preuba (1)
assertValue("importeTotal", "0,00"); // Sin detalles el importe total es 0
execute("Sections.change", "activeSection=1");
assertCollectionRowCount("pedidos", 0);
execute("Factura.anyadirPedidos", // Cuando mostramos la lista de pedidos (2) ...
"viewObject=xava_view_section1_orders");
confirmarClienteEnTodasFilas(numeroCliente);
confirmarValorEnTodasFilas(12, "Entregado");
String importeTotalPrimerPedido = getValueInList(0, 7); //..tomamos nota del importe
int cantidadPedidos = getListRowCount(); // base del primer pedido de la lista (3)
...
assertCollectionRowCount("pedidos", 1);
execute("Sections.change", "activeSection=0");
assertCollectionNotEmpty("detalles"); // Hay detalles, han sido copiados (4)
assertValue("importeTotal", importeTotalPrimerPedido); // El importe total de la factura
execute("Sections.change", "activeSection=1"); // coincide con el del
// pedido recién añadido (5)
...
execute("Sections.change", "activeSection=0"); // Volvemos a la pestaña de detalles de la factura
eliminarFilas(); // Eliminamos las filas que se agregaron (6)
waitAJAX(); // Esperamos que se completen los procesos JS de fondo
assertCollectionRowCount("detalles", 0); // Verificamos nuevamente que no hayan filas
assertValue("importeTotal", "0,00");
execute("CRUD.save");
}
Primero, Verificamos que la factura para esta prueba no tiene detalles (1), después añadimos un pedido (2), tomando nota de su importe total (3), entonces verificamos que la factura actual tiene detalles (4) y que su importe total es el mismo que el del pedido añadido (5), por último borramos las filas que tiene detalles (6). Agregamos el siguiente código en la misma clase de PruebaFactura:protected void eliminarFilas() throws Exception {
// contamos la cantidad de filas que hay en la tabla, para este ejemplo debemos tener menos de 100 elementos en la tabla
int contador = getHtmlPage().getElementById("ox_facturacion_Factura__detalles") // (1)
.getChildElements().iterator().next().getChildElementCount()-7; //(2)
for (int i=0; i < contador; i++) {
HtmlElement boton = (HtmlElement)getHtmlPage().getElementById("ox_facturacion_Factura__detalles___0") // (3)
.getChildElements().iterator().next()
.getChildElements().iterator().next()
.getChildElements().iterator().next()
.getChildElements().iterator().next(); // (4)
boton.click(); // (5)
}
}
public void testAnyadirPedidos() throws Exception {
login("admin", "admin");
assertListNotEmpty();
execute("List.orderBy", "property=numero");
execute("List.viewDetail", "row=0");
String numeroCliente = getValue("cliente.numero");
assertCollectionRowCount("detalles", 0);
assertValue("importeTotal", "0,00");
execute("Sections.change", "activeSection=1");
assertCollectionRowCount("pedidos", 0);
execute("Factura.anyadirPedidos",
"viewObject=xava_view_section1_pedidos");
confirmarClienteEnTodasFilas(numeroCliente);
confirmarValorEnTodasFilas(12, "Entregado");
String importeTotalPrimerPedido = getValueInList(0, 7);
int cantidadPedidos = getListRowCount();
execute("AnyadirPedidosAFactura.add", "row=0");
assertMessage("1 elemento(s) añadido(s) a Pedidos de Factura");
assertCollectionRowCount("pedidos", 1);
execute("Sections.change", "activeSection=0");
assertCollectionNotEmpty("detalles");
assertValue("importeTotal", importeTotalPrimerPedido);
execute("Sections.change", "activeSection=1");
execute("Factura.anyadirPedidos",
"viewObject=xava_view_section1_pedidos");
assertListRowCount(cantidadPedidos - 1);
execute("AddToCollection.cancel");
checkRowCollection("pedidos", 0);
execute("Collection.removeSelected",
"viewObject=xava_view_section1_pedidos");
assertCollectionRowCount("pedidos", 0);
execute("Sections.change", "activeSection=0");
eliminarFilas();
waitAJAX();
assertCollectionRowCount("detalles", 0);
assertValue("importeTotal", "0,00");
execute("CRUD.save");
}
Hemos finalizado el código de las pruebas automáticas. Ahora puedes ejecutar todas las pruebas de tu proyecto. Han de salir en color verde.