En los últimos días me encontré dos
veces conversando sobre pruebas que incluyen fechas: en el curso
sobre Fitnesse, con pruebas funcionales, y con mis compañeros en UTI
SIS con TDD.
Ambas conversaciones me hicieron
repensar este tema, y aprovecho para volcar mi visión actual.
¿Por qué es especial la prueba que involucra a fechas?
Hay otras razones,
pero en este post me centraré en la dependencia con la fecha del
sistema. Esta dependencia puede darse en dos situaciones:
- crear la entidad o realizar una acción sobre la misma (emitir un documento legal, como un cheque o una factura), que asigna la fecha del sistema a algún campo de una entidad u objeto de la aplicación.
- consultar a la entidad u objeto, siendo el resultado de la consulta dependiente de la fecha (posiblemente la fecha actual).
Ejemplos:
- Un cheque se emite al día de hoy (fecha de emisión), y vence en 30 días.
- Quiero consultar si puedo depositar el cheque (no debe estar vencido).
Si hacemos pruebas
que tengan dependencias sobre un elemento que no podemos controlar
(en este caso el paso del tiempo), nuestras pruebas van a ser poco
robustas (como pruebas unitarias).
Si quiero probar
el sistema completo, me puede interesar explicitar el uso de las
fechas de diferentes servidores. Estaría haciendo prueba de
integración en vez de prueba unitaria.
¿Que alternativas tengo?
- Usar los datos de la prueba de manera que el estado o condición a probar sea válida al día de hoy.
- En el caso del cheque, es fácil probar si el cheque puede depositarse (no está vencido), ya que si creamos un cheque hoy, seguro está dentro del período.
- Probar el caso de cheque vencido es más complejo: quizás puedo modificar la fecha en la base de datos.
- Se puede tener una generación automática de datos de prueba de manera que se cumplan las condiciones deseadas.
- Disponer de una manera de modificar la fecha que toma el sistema como fecha actual.
- Se puede tener los datos con fechas fijas y lo que se cambia es la fecha simulada del sistema. Se requiere cambiar al sistema, para probarlo.
- Ampliar la funcionalidad de manera de recibir la fecha de referencia (en vez de tomarla del sistema)
- Es conflictivo si el cliente no siente esto como necesario, parece ser complejidad adicional, sólo algo para facilitar las pruebas.
- Generalmente sirve para el caso de las consultas, no de la generación.
- Realizar pruebas relativas.
- No usar valores absolutos de fechas u horas. Esto tiene el inconveniente que (similar al caso 1), que no se puede acelerar el paso del tiempo: por ejemplo, si mi datos tiene precisión de días, y quiero probar el próximo día.
Ejemplos
Alternativa 1
TDD
El siguiente ejemplo, en PHP, muestra
como se preparan los datos para las pruebas relacionadas con cursos,
en la que hay 4 fechas (inicio y fin de la inscripción, inicio y fin
del curso). Los primeros 4 números 'datos' son días relativos al
día de hoy.
La función __creaCurso traduce entre
valores relativos de las fechas y los valores absolutos con que se
quiere probar.
function testCursosActuales() {
$pruebas = array(
array('datos' => array(
1, 1, 3, 3,false,false), 'actual' => False),
array('datos' => array(
1, 1, 3, 3,true,false), 'actual' => True),
array('datos' => array(
0, 0, 2, 2,true,false), 'actual' => True),
array('datos' =>
array(-1,-1, 1, 1,true,false), 'actual' => True),
array('datos' =>
array(-1,-1, 1, 1,true,true), 'actual' => True),
array('datos' =>
array(-2,-2, 0, 0,true,true), 'actual' => True),
array('datos' =>
array(-3,-3,-1,-1,true,true), 'actual' => False),
array('datos' =>
array(-5,-3,-1,-1,false,true), 'actual' => False)
);
foreach($pruebas as $prueba) {
$id =
$this->__creaCurso($prueba['datos']);
…
$this->assertEqual($prueba['actual'], $resultado);
}
Fitnesse
Dentro de una página se puede usar
!today, que se reemplaza por la fecha / hora actual. También se
pueden poner fechas relativas (!today -1).
Alternativa 2
En este caso, la forma de cubrir esto
es la Inversión de Control / Inyección de Dependencias. Se debe
utilizar el servicio de obtención de día y hora actual a traves de
una capa de abstración, de manera de poder reemplazarlo por una
implementación controlada por las pruebas. Un ejemplo de esto se
muestra en el capítulo 15 del libro FIT for Developing Software.
El SUT debe estar preparado (o debemos
poder modificarlo para) para recibir la referencia al servicio.
Alternativa 3
En muchos casos el usuario pide
funcionalidad que depende de la fecha actual, pero esa funcionalidad
podría generalizarse para una fecha abitraria, con valor de negocio.
Por ejemplo, cheque a depositar. Tiene sentido con fecha de hoy, pero
si puedo poner fechas futuras, ayuda a la planificación.
Se puede evitar el aumento de la
complejidad para el caso más usado con valores por defecto
apropiados.
Alternativa 4
Puedo probar que un evento esté en
intervalos temporales. Por ejemplo si quiero probar que un registro
de auditoría es correcto, puedo almacenar el horario previo y
posterior a la operación, y verificar que el registro esté dentro
de ese intervalo.
No hay comentarios:
Publicar un comentario