Documentos de Académico
Documentos de Profesional
Documentos de Cultura
00927tfc PDF
00927tfc PDF
09
Fecha de entrega
14/01/2009
2
5.3. Juego de pruebas............................................................................................................................ 47
6. Conclusiones......................................................................................................... 51
Uso de metodología ágil........................................................................................................................... 51
Ciclos de desarrollo cortos.....................................................................................................................51
Pruebas de unidad automatizadas .....................................................................................................51
Metodología de tests y herramientas.............................................................................................. 52
7. Bibliografía ........................................................................................................... 52
3
1. Introducción
Según el Foro Internacional de Turismo, las compras de viajes por Internet han
crecido de forma significativa hasta el punto de llevar a la crisis a las agencias de
viaje tradicionales. La tendencia se presenta como consolidada aunque ello no
tiene por qué suponer la desaparición de estas agencias sino un cambio en su
concepción original de manera que se puedan adaptar a los nuevos tiempos.
Las compañías aéreas y las centrales de reservas de hoteles fueron algunas de las
primeras entidades en usar grandes sistemas en red para gestionar la reserva y
venta de sus productos. Estos sistemas conectaban los ordenadores centrales con
los terminales de las Agencias de Viajes. Éstas por su parte vendían luego el
producto al público final llevándose una comisión por la gestión.
4
Las compañías de viajes (ferroviarias, aéreas, de alquiler de coches…), los hoteles,
guías y otros muchos servicios que antes dependían de una agencia u organizador
de viajes, ahora pueden ofertarse directamente en la red, sin intermediarios y sin
monopolios que limiten su actividad comercial, de manera que se ponen en manos
de una buena gestión para ofrecer la mejor opción al cliente y del marketing.
El sistema de reservas que elaboraremos en este proyecto contará con una ventaja
competitiva frente a los sistemas de las grandes mayoristas tradicionales. Nuestra
tecnología estará basada en la potencia de Java y J2EE y utilizará metodologías
ágiles apoyadas en tests automatizados con las que podremos ser más dinámicos
frente a los cambios que puedan surgir en el futuro.
Por otro lado, también será deseable que la aplicación sea testable con facilidad,
para ello construiremos una arquitectura en la que los objetos de negocio se
puedan ejecutar tanto fuera como dentro del contenedor J2EE, para así poderlo
someter a todas las pruebas necesarias, sin la complicación, y lentitud añadida de
arrancar un servidor J2EE.
5
código corremos el riesgo de estropearlo. Por ello debemos utilizar las tecnicas de
herencia y composición para añadir funcionalidad a nuestros programas.
Para este proyecto exploraremos cómo aplicar las principales prácticas de lo que
se conoce como “desarrollo ágil”.
6
ejecución sobre la planificación. A medida que se profundiza en el conocimiento de
un problema se cambian los planes. Cuando el cliente vea nuestras propuestas, se
le ocurriran nuevas ideas que cambiarán los planes. Cuando profundicemos en el
conocimiento de nuevas teconologías haremos descubrimientos que cambiarán de
nuevo los planes.
Este proyecto será ágil porque tendremos que tratar con cierta incertidumbre
tecnológica al tener que evaluar la tecnología J2EE y el gestor de bases de datos
PostgreSQL.
El desarrollo ágil no equivale al caos. Para poderse llevar a cabo necesita basarse
en en dos pilares: pruebas automáticas y retroalimentacion (feedback)
temprana, es decir objetivos palpables a corto plazo.
Manifiesto ágil:
Valorar más a los individuos y su interacción que a los procesos y las herramientas
Este es posiblemente el principio más importante del manifiesto. Por supuesto que los procesos ayudan al
trabajo. Son una guía de operación. Las herramientas mejoran la eficiencia, pero sin personas con
conocimiento técnico y actitud adecuada, no producen resultados.
Las empresas suelen predicar muy alto que sus empleados son lo más importante, pero la realidad es que
en los años 90 la teoría de producción basada en procesos, la re-ingeniería de procesos ha dado a éstos
más relevancia de la que pueden tener en tareas que deben gran parte de su valor al conocimiento y al
talento de las personas que las realizan.
Los procesos deben ser una ayuda y un soporte para guiar el trabajo. Deben adaptarse a la organización, a
los equipos y a las personas; y no al revés. La defensa a ultranza de los procesos lleva a postular que con
ellos se pueden conseguir resultados extraordinarios con personas mediocres, y lo cierto es que este
principio es peligroso cuando los trabajos necesitan creatividad e innovación.
7
Valorar más el software que funciona que la documentación exhaustiva
Poder ver anticipadamente como se comportan las funcionalidades esperadas sobre prototipos o sobre las
partes ya elaboradas del sistema final ofrece una retroalimentación (feedback) muy estimulante y
enriquecedor que genera ideas imposibles de concebir en un primer momento; difícilmente se podrá
conseguir un documento que contenga requisitos detallados antes de comenzar el proyecto.
El manifiesto no afirma que no hagan falta. Los documentos son soporte de la documentación, permiten
la transferencia del conocimiento, registran información histórica, y en muchas cuestiones legales o
normativas son obligatorios, pero se resalta que son menos importantes que los productos que funcionan.
Menos trascendentales para aportar valor al producto.
Los documentos no pueden sustituir, ni pueden ofrecer la riqueza y generación de valor que se logra con
la comunicación directa entre las personas y a través de la interacción con los prototipos. Por eso, siempre
que sea posible debe preferirse, y reducir al mínimo indispensable el uso de documentación, que genera
trabajo que no aporta un valor directo al producto.
Si la organización y los equipos se comunican a través de documentos, además de perder la riqueza que
da la interacción con el producto, se acaba derivando a emplear a los documentos como barricadas entre
departamentos o entre personas.
8
mitad del desarrollo y tener garantías de no haber estropeado nada?
Las pruebas, por tanto nos permiten afrontar con mayores garantías el cambio. Además
el hecho de que sean automatizadas nos permite repetirlos infinidad de veces sin
encarecer el coste de desarrollo.
Supongamos que hemos ejecutado la suite unas 500 veces (ejecuto la suite varias veces
mientras desarrollo) Si un programador tuviese que depurar a mano esas pruebas
tardaría 140 * 500 * 2 minutos por prueba = 140.000 minutos, o lo que es lo mismo 291
jornadas de trabajo.
Eso suponiendo que el programador que ejecutase las pruebas no se equivocase nunca y
fuese tan perfecto como las pruebas automáticas.
Sin embargo, por poner un ejemplo, si un programa tiene 6 controles con 4 valores de
entrada posibles para dar un resultado determinado, probarlo solo con una prueba de
integración nos obligaría a escrib ir 4 * 4 * 4 * 4 * 4 * 4 , pruebas que son las distintas
posibilidades de entrada que tendría el sistema, o lo que es lo mismo 4 ^ 6 = 46.656
9
pruebas diferentes.
Con las pruebas de unidad podemos probar estos componentes individualmente, es decir
probaríamos el primer control, para lo que escribiríamos cuatro pruebas para sus cuatro
posibles valores de entrada. Haríamos lo mismo con los 5 controles restantes con lo que
escribiríamos 4 pruebas para cada uno, en total
Normalmente en todas las pruebas el primer paso ha sido probar que hace lo que tiene
que hacer con los valores esperados.
Luego normalmente se han probado con valores nulos, cadenas vacías y valores límite.
No hemos probado todas las clases, solo las que tenían cierta complejidad.
Habitualmente se ha hecho una prueba por método aunque en algunos casos se han
tenido que hacer más.
1.3.2.2. Documentación.
En cuanto a la documentación, no hemos prescindido de ella, hemos constatado que
son de gran utilidad los casos de uso bien documentados junto con diagramas de
actividad UML.
10
Nos han sido especialmente útiles para describir el comportamiento de los
controladores de cada uno de los casos de uso.
Los diagramas nos han ayudado a mejorar la productividad ya que permitían centrarse
en la funcionalidad que se estaba desarrollando y dejar de lado las preocupaciones de
las subsiguientes tareas.
No nos han parecido útiles sin embargo los diagramas de clases, de colaboración y de
secuencia., y por tanto no los he mos usado. Esto es porque siempre hemos usado los
mismos patrones: MVC , Façade, Decorators, Factorys y DAO..
Antes de empezar tan siquiera a hacer los casos de uso Instalaremos las siguientes
herramientas:
11
1.4.3.1. Sprint1. Transaccion de reserva de plazas.
Al ser la parte mas crítica, la de la gestión de las reservas con transacciones, se hará en
primer lugar para despejar todas las incertidumbres al respecto. Se harán pruebas de
estrés para asegurar el bue n rendimiento de la solución adoptada.
12
1.5. Productos obtenidos
1.5.1. Metodología y herramientas de testing
A través de la experiencia obtenida en el desarrollo de este proyecto, hemos
llegado a desarrollar una metodología de testing que resuelve algunos de los
problemas habituales en la implantación de pruebas automatizadas.
13
Ilustración 1 Aislamiento del código de pruebas del de producción
14
Utilidades para pruebas
Se han creado unas clases de utilidad que pueden ser reutilizadas en cualquier otro
proyecto estas clases están en el paquete com.dblanch.testutils
Tabla 1 Test utils
La solución que hemos hallado está en la clase SQLUtil con sus dos métodos.
El método SQLUtil.executeBatch(String file) permite la ejecución de un fichero
batch sql, que usamos usado para preparar el estado de la base de datos para las
pruebas.
El método SQLUtil.queryInteger(String sql) ejecuta una sentencia sql que ha de
devolver un entero. Como por ejemplo un SELECT COUNT(*), Luego ese valor se
usará para verificar las pruebas.
A continuación mostramos un ejemplo del uso de esta clase para las pruebas:
public void testReservaNormal() throws Exception {
commandPostgresql.doReserva(reserva);
15
connection.commit();
connection.close();
}
Al menos hasta ahora hemos podido probar todo que nos ha hecho falta.
Por ejemplo, si en la prueba anterior hubiésemos querido comprobar que se
habían insertado todos los atributos en sus correspondientes campos, podríamos
haber escrito la sentencia sql del método de este otro modo :
SELECT COUNT(*) FROM RESERVA WHERE ID_OFERTA=1 AND ID_CLIENTE=1
AND PLAZAS_RESERVADAS=1
16
1.5.2. Entrega del producto
17
1.1.1.1. Navegación por las Pantallas
La primera pantalla de la aplicación es la del listado de viajes. Nos permite filtrar
por todos los campos de la forma que queramos.
18
Si no estamos logados, al hacer click sobre un elemento de la lista se nos mostrará
la pantalla de login.
Ilustración 5 Login
19
Comprueba si existe el usuario y si la contraseña es correcta.
Una vez logado, el sistema nos lleva al elemento de la lista que habíamos
seleccionado y que disparó este evento.
20
El sistema comprueba que el valor introducido es correcto, rechazándolo si no es
así.
21
Si se piden mas plazas de las que se ofrecen pero queda todavía alguna plaza, el
sistema nos deja pedir una cantidad menor.
Si no queda ninguna plaza el sistema nos informa del hecho y no nos deja mas
opción que volver a la pantalla inicial.
22
En el proceso de Login, también podíamos haber elegido darnos de alta como
usuario nuevo. El sistema hace las habituales comprobaciones de los datos de
entrada.
23
2. Especificación y requerimientos
2.1. Información inicial
Queremos crear un sistema reservas on-line para una agencia de viajes. El negocio
de una agencia de viajes es la venta de paquetes turísticos que consisten en una
combinación de diferentes servicios (transporte, alojamiento, excursiones, guías,
etc.…) en un solo producto.
El paquete turístico consta de un código interno, un nombre, un precio por
persona, una descripción, una presentación más o menos elaborada y un número
de plazas ofertadas.
El sistema de reservas debe ofrecer un catálogo de paquetes turísticos por el que
se pueda buscar por diferentes criterios, como fechas de salida, duración del viaje,
precio, etc.
Cuando un cliente hace una reserva, el sistema debe actualizar el número de plazas
disponibles, restando las que el cliente ha reservado, evitando que se puedan
solicitar más plazas de las existentes.
El sistema debe guardar con la reserva, el nombre del cliente, el paquete solicitado
y el número de plazas que quiere.
El sistema debe permitir la inclusión futura con de una interfaz con medios de
pago electrónico.
El sistema tiene que permitir la introducción de paquetes turísticos en el catálogo,
su modificación, consulta y borrado. La modificación y el borrado solo se podrán
hacer si no se ha vendido ninguna reserva.
El sistema tiene que permitir el registro de los clientes donde introducirán
información sobre sus datos personales, tarjetas de crédito, etc. También la
modificación, consulta y borrado.
El sistema tiene que manejar de manera óptima las transacciones, minimizando
bloqueos y asegurando la consistencia.
2.2. Glosario
Oferta: Producto en venta por la agencia de viajes
24
2.3. Modelo del dominio
• Oferta:
o Nombre
o Descripción
o Fecha de Inicio
o Fecha de Fin
o Duración
o Plazas Disponibles
o Plazas Totales
• Reserva
o Oferta
o Cliente
• Cliente
o Nombre
o Apellidos
o Login
o Password
o Fecha de Alta
25
2.4. Diagrama de casos de uso
Caso de uso:
Flujo principal:
26
2 El sistema pregunta su nombre de usuario y contraseña
Flujo alternativo:
Explicación:
Usuario
Flujo principal:
27
• descripción (criterio: contiene palabra)
• duración (criterio: igual a con dos días por arriba y dos días por abajo)
Flujo alternativo:
Puntos de extensión:
Requisitos no funcionales:
El sistema debe ser rápido en devolver los resultados. Esto implica que la
transacción debe permitir hacer lecturas sucias, ya que es mas importante la
velocidad de respuesta que la exactitud del contenido.
Temas pendientes:
28
Usuario
Disparador:
El usuario ha seleccionado una de las ofertas existentes que tienen disponibilidad
de plaza en ese momento.
Precondición:
Flujo principal:
Flujo alternativo:
Poscondición:
Requisitos no funcionales:
29
Las transacciones deben ser rápidas y correctas., por lo que deben bloquear la
lectura de plazas para luego poder actualizarla, restando las plazas, pero el mínimo
tiempo posible para permitir que otras transacciones operen sobre el mismo
registro.
La transacción tiene que ser segura, no puede ser falsificable alterando parámetros
de la petición.
2.5.3. Login
Disparadores:
Flujo principal:
• nombre de usuario
• password
Flujo alternativo:
Requisitos no funcionales:
En ningún caso debe intercambiarse entre el navegador y el servidor el nombre de
usuario y/o la contraseña una vez pasada la validación, para evitar suplantación de
identidad o robo de contraseña.
Temas pendientes:
Hacer que el proceso de autenticación vaya encriptado con SSL (estimar el coste)
Hacer que el password de usuario vaya encriptado dentro de la base de datos
(estimar coste)
30
2.5.4. Mantenimiento cuenta de usuario
Disparadores:
Flujo principal:
Flujo alternativo:
Requisitos no funcionales:
En ningún caso debe ser visible el nombre de usuario y/o la contraseña una vez
pasada la validación.
Temas pendientes:
Hacer que el proceso de alta vaya encriptado con SSL (estimar el coste)
31
Hacer que la contraseña de usuario vaya encriptada dentro de la base de datos
(estimar coste)
Requerir una contraseña con un nivel de seguridad aceptable es decir con un
número de caracteres suficientes, que contenga números, etc. (estimar coste)
Flujo principal:
• nombre
• apellidos
• login
• password
Flujo alternativo:
Puntos de extensión:
Modificar usuario.
Precondición:
El usuario se ha logado en el sistema previamente con lo que tiene accesible la
opción de mantenimiento de cuenta de usuario.
Flujo principal:
32
1) El sistema recupera los datos del usuario y muestra una pantalla con los
campos de:
• nombre
• apellidos
• login
• password
Flujo alternativo:
Temas pendientes:
Hacer que el proceso de modificación vaya encriptado con SSL (estimar el coste).
Hacer que la contraseña de usuario vaya encriptada dentro de la base de datos
(estimar coste).
Requerir una contraseña con un nivel de seguridad aceptable es decir con un
número de caracteres suficientes, que contenga números, etc. (estimar coste).
Flujo principal:
33
3) El usuario acepta
4) El sistema escribe en fecha de baja el día de hoy, con lo que queda registrada la
baja. (baja lógica) y devuelve al usuario a la pantalla de inicial de la aplicación.
Flujo alternativo:
Flujo alternativo:
34
1) El sistema informa de los errores y devuelve al punto 2 con los datos que
rellenó el usuario.
Flujo alternativo:
Requisitos no funcionales:
En el listado deben salir todas las ofertas pero deberíamos evitar las lecturas
sucias, ver el nivel de aislamiento optimo de transacciones.
35
2.6. Requisitos de la interfaz de usuario
La interfaz de usuario será HTML, ya que es una aplicación Web. Prescindiremos
de javascript, porque el usuario lo puede desactivar. Evitaremos los diseños
complicados para que el tratamiento de pruebas con httpUnit sea posible.
Haremos hincapié en que la navegación esté muy controlada. La navegación ha de
permitir buscar los viajes y solo cuando se seleccione uno, nos pedirá logarnos, o
darnos de alta en el sistema.
El sistema ha de ser amigable, en particular a la hora de mostrar los errores de
validación de los formularios. Estos tienen que presentarse al lado del mismo
campo que originó el error.
3. Análisis
3.1. Identificación de las clases de entidades y sus atributos
36
3.2. Diagramas de estados
37
3.3.2. Reserva de plaza (búsqueda + reserva)
38
3.3.3. Login
39
3.3.4. Alta de usuario
40
3.3.5. Integración (búsqueda, Login, alta, reserva)
41
4. Diseño técnico
A la arquitectura habitual de Struts, le hemos añadido unas clases que han simplificado
el desarrollo en gran medida. En estas clases hemos invertido mucho tiempo en pruebas
ya que según nuestra experiencia es en la validación de los datos del us uario, donde mas
suelen fallar las aplicaciones.
En nuestra aplicación el método validate del ActionForm se hace sólo con métodos de
la clase Validator.
Clase: com.dblanch.utils.Validator
Responsabilidad: validar las entradas de los campos de los ActionForm, que son
siempre strings
Clase: com.dblanch.utils.Parser
42
43
4.2. El modelo
4.2.1. La Fachada
Hemos mentido un poco, nuestra fachada no es puramente una fachada, hace algo
mas que delegar los métodos, obtiene un objeto java.sql.Connnection y se los pasa
a los objetos en los que delega. También se encarga de gestionar la transacción y
cerrar la conexión una vez terminado con el método.
Esto lo hace implementando otro Patrón que es el Template. El método
java.sql.Connection getConnection() es abstracto y las clases hijas lo implementan
de diferente forma.
La forma de obtener la conexión a la base de datos en un contenedor J2EE es
distinta a la forma de hacerlo fuera. En un contenedor se localiza un DataSource
que provee un pool1 de conexiones registrado bajo un nombre2.
44
Como vemos en el diagrama hemos implementado dos ModelFacade. Uno para el
servidor Tomcat y otro para Test, con este último es con el que usamos para
realizar las pruebas.
Aún queda un punto de complejidad por explicar, el objeto ModelFacadeTomcat no
se instancia directamente con un operador new. Si no que hemos usado una clase
Factory para instanciarlo.
La razón detrás de esta aparente complejidad es que esta arquitectura nos permite
poder cambiar el objeto de implementación ModelFacade por otro que podría ser
un ModelFacadeMock, por ejemplo.
45
Los Mock objects son objetos que no implementan funcionalidad real y sirven solo
para pruebas.Los métodos que devuelven datos del objeto Mock, devuelven
también objetos Mock. Esta estrategia se puede usar para desarrollar la parte web,
sin depender de unos datos de la base de datos o para poder trabajar en la parte
web, sin tener terminada la parte del modelo. Así se puede trabajar en paralelo en
ambas partes.
Para cambiar de implementación de ModelFacade, sólo habría que cambiar el
Factory.
5. Implementación
5.1. Herramientas de desarrollo
Java 1.6
Tomcat
46
5.2. Proceso de instalación
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
/reservasWeb/WebContent/WEB-INF/lib
/reservasLibs
47
Suite de pruebas de unidad (junit);
/reservasTest/src/com/dblanch/suite/AllTests.java
/reservasTest/src/com/dblanch/integración/IntegracionTest.java
Pruebas de rendimiento;
/reservasTest/src/com/dblanch/integración/RendimientoEscrituraADisco.java
/reservasTest/src/com/dblanch/integración/RendimientoTransacciones.java
/reservasTest/src/com/dblanch/integración/TransaccionesMultithread.java
48
<testcase name="testParseInteger"
classname="com.dblanch.utils.ParserTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.cliente.ClienteVOTest" time="0.004">
<testcase name="testToString"
classname="com.dblanch.cliente.ClienteVOTest" time="0.004" />
</testsuite>
<testsuite name="com.dblanch.cliente.ClienteDAOTest" time="0.083">
<testcase name="testAddDuplicate"
classname="com.dblanch.cliente.ClienteDAOTest" time="0.028" />
<testcase name="testAdd" classname="com.dblanch.cliente.ClienteDAOTest"
time="0.017" />
<testcase name="testFindClienteByLoginAndPassword"
classname="com.dblanch.cliente.ClienteDAOTest" time="0.038" />
</testsuite>
<testsuite name="All tests" time="0.495">
<testsuite name="com.dblanch.oferta.OfertaDAOTest" time="0.058">
<testcase name="testFindOfertas"
classname="com.dblanch.oferta.OfertaDAOTest" time="0.042" />
<testcase name="testFindOfertaByPk"
classname="com.dblanch.oferta.OfertaDAOTest" time="0.016" />
</testsuite>
<testsuite name="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.003">
<testcase name="testSetNombre"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.001" />
<testcase name="testSetDescripcion"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.0" />
<testcase name="testSetFechaInicio"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.0" />
<testcase name="testSetFechaFin"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.001" />
<testcase name="testSetPlazasDisponibles"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.0" />
<testcase name="testSetDuracion"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.0" />
<testcase name="testComposeSQL"
classname="com.dblanch.oferta.OfertaQueryBuilderTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.reserva.ReservaCommandTest" time="0.283">
<testcase name="testReservaNormal"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.028" />
<testcase name="testReservaPlazasInsuficientes"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.027" />
<testcase name="testReservaNingunaPlaza"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.119" />
<testcase name="testUpdateOferta"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.109" />
</testsuite>
<testsuite
name="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.007">
<testcase name="testNingunCritierioDeBusqueda"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.005"
/>
<testcase name="testFechaInicio"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.0"
/>
<testcase name="testFechaFin"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.001"
/>
<testcase name="testPlazasDisponiblesNoValido"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.001"
/>
<testcase name="testDuracionNoValido"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.0"
/>
</testsuite>
<testsuite name="com.dblanch.utils.ValidatorTest" time="0.003">
<testcase name="testFechaValida"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
<testcase name="testRangoFechasCorrecto"
classname="com.dblanch.utils.ValidatorTest" time="0.001" />
<testcase name="testNumeroNatural"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
<testcase name="testValorNulo"
classname="com.dblanch.utils.ValidatorTest" time="0.002" />
<testcase name="testExceedsMaxSize"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
49
<testcase name="testNotReachMinSize"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
</testsuite>
<testsuite name="com.dblanch.utils.ParserTest" time="0.001">
<testcase name="testParseDate"
classname="com.dblanch.utils.ParserTest" time="0.001" />
<testcase name="testParseInteger"
classname="com.dblanch.utils.ParserTest" time="0.0" />
</testsuite>
<testsuite name="com.dblanch.frontend.SystemFacadeAbstractTest"
time="0.051">
<testcase name="testFindOfertas"
classname="com.dblanch.frontend.SystemFacadeAbstractTest" time="0.028" />
<testcase name="testAddClienteTest"
classname="com.dblanch.frontend.SystemFacadeAbstractTest" time="0.023" />
</testsuite>
<testsuite name="com.dblanch.reservasweb.reserva.ReservaFormTest"
time="0.001">
<testcase name="testPlazasDeseadasValido"
classname="com.dblanch.reservasweb.reserva.ReservaFormTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.cliente.ClienteVOTest" time="0.001">
<testcase name="testToString"
classname="com.dblanch.cliente.ClienteVOTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.cliente.ClienteDAOTest" time="0.087">
<testcase name="testAddDuplicate"
classname="com.dblanch.cliente.ClienteDAOTest" time="0.025" />
<testcase name="testAdd"
classname="com.dblanch.cliente.ClienteDAOTest" time="0.026" />
<testcase name="testFindClienteByLoginAndPassword"
classname="com.dblanch.cliente.ClienteDAOTest" time="0.036" />
</testsuite>
</testsuite>
<testsuite name="com.dblanch.reservasweb.cliente.ClienteParserTest" time="0.001">
<testcase name="testParse"
classname="com.dblanch.reservasweb.cliente.ClienteParserTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest"
time="0.003">
<testcase name="testNingunCritierioDeBusqueda"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.001"
/>
<testcase name="testFechaInicio"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.0"
/>
<testcase name="testFechaFin"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.001"
/>
<testcase name="testPlazasDisponiblesNoValido"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.001"
/>
<testcase name="testDuracionNoValido"
classname="com.dblanch.reservasweb.busquedaofertas.BusquedaOfertasFormTest" time="0.0"
/>
</testsuite>
<testsuite name="com.dblanch.reservasweb.reserva.ReservaFormTest" time="0.0">
<testcase name="testPlazasDeseadasValido"
classname="com.dblanch.reservasweb.reserva.ReservaFormTest" time="0.0" />
</testsuite>
<testsuite name="com.dblanch.reserva.ReservaCommandTest" time="0.104">
<testcase name="testReservaNormal"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.022" />
<testcase name="testReservaPlazasInsuficientes"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.022" />
<testcase name="testReservaNingunaPlaza"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.027" />
<testcase name="testUpdateOferta"
classname="com.dblanch.reserva.ReservaCommandTest" time="0.032" />
</testsuite>
<testsuite name="com.dblanch.utils.ValidatorTest" time="0.004">
<testcase name="testFechaValida"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
<testcase name="testRangoFechasCorrecto"
classname="com.dblanch.utils.ValidatorTest" time="0.001" />
<testcase name="testNumeroNatural"
classname="com.dblanch.utils.ValidatorTest" time="0.003" />
50
<testcase name="testValorNulo"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
<testcase name="testExceedsMaxSize"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
<testcase name="testNotReachMinSize"
classname="com.dblanch.utils.ValidatorTest" time="0.0" />
</testsuite>
<testsuite name="com.dblanch.oferta.OfertaVOTest" time="0.001">
<testcase name="testGetDuracion"
classname="com.dblanch.oferta.OfertaVOTest" time="0.001" />
</testsuite>
<testsuite name="com.dblanch.oferta.OfertaDAOTest" time="0.086">
<testcase name="testFindOfertas"
classname="com.dblanch.oferta.OfertaDAOTest" time="0.06" />
<testcase name="testFindOfertaByPk"
classname="com.dblanch.oferta.OfertaDAOTest" time="0.026" />
</testsuite>
</testrun>
6. Conclusiones
51
complejidad de una prueba completa de integración crece exponencialmente en
función del número de componentes sobre los que opere, mientras que el coste de
las pruebas de unidad es lineal
En definitiva, creemos que las pruebas de unidad deben ser un paso necesario en
todo desarrollo de software.
7. Bibliografía
Head First Design Patterns, Eric Freeman &Elisabeth Freeman Editorial O’Reilly
52