Definición
Las
siguientes definiciones son algunas de las recogidas en el diccionario IEEE en
relación a las pruebas [IEEE, 1990], que complementamos con otras más
informales:
Pruebas: "una actividad en la cual un sistema o uno de sus
componentes se ejecuta 2 en circunstancias previamente especificadas, los
resultados se observan y registran y se realiza una evaluación de algún
aspecto". Para Myers [MYERS, 1979], probar (o la prueba) es el
"proceso de ejecutar un programa con el fin de encontrar errores".
El nombre "prueba", además de la
actividad de probar, se puede utilizar para designar "un conjunto de casos
y procedimientos de prueba" [IEEE, 1990].
Caso de prueba : "un conjunto de entradas, condiciones de
ejecución y resultados esperados desarrollados para un objetivo particular como, por ejemplo, ejercitar un camino
concreto de un programa o verificar el cumplimiento de un determinado
requisito". "También se puede referir a la documentación en la que se
describen las entradas, condiciones y salidas de un caso de prueba".
Defecto: "un defecto en el software como, por ejemplo, un
proceso, una definición de datos o un paso de procesamiento incorrectos en un
programa".
Fallo: "La incapacidad de un sistema o de alguno de sus
componentes para realizar las funciones requeridas dentro de los requisitos de
rendimiento especificados".
Conceptos
fundamentales
Verificación:
- Consiste en responder a la pregunta: ¿Estamos
construyendo el producto correctamente? Dada la especificación
que hemos tomado del usuario ¿estamos construyendo bien el código?
- ¿El resultado final del desarrollo software
concuerda con la especificación (requisitos) del sistema? Hay que intentar
asegurar que el desarrollo final coincide con dicha especificación
Validación:
- ¿Estamos construyendo el producto correcto?
- ¿El resultado final del desarrollo software se
ajusta a lo que el usuario quería (sus necesidades)? En la mayoría de las
ocasiones el producto desarrollado no casa con la ideas del cliente,
normalmente porque a éste suele faltarle capacidad técnica de expresión.
¿Cómo llevar a cabo la verificación y
validación? Métodos
- Pruebas del software (Dinámico): consisten en ejecutar comprobando que distintos valores de entrada producen los resultados deseados.
- Métodos de inspección del software (Estático): se basan en la revisión de la documentación,
requisitos, incluso código sin ejecutar nada. Esta tarea puede realizarse
por un grupo de expertos por ejemplo.
- Hay un tipo concreto de métodos estáticos
llamados métodos formales. Éstos se basan en realizar una especificación
llevada al extremo transformando el software a lenguaje matemático, donde
no quedan ambigüedades y el código queda bien especificado.
- Otra forma de inspección del software es
comprobando el código mediante heurísticas con algún programa que la aplica
(P. ej.- Findbugs).
Tipos de prueba (categorización)
- En
función de qué conocemos:
- Pruebas de caja negra: no conocemos la implementación del código, sólo la interfaz. Tan sólo podemos probar dando distintos valores a las entradas y salidas.
- Pruebas de caja blanca: conocemos
el código (la implementación de éste) que se va a ejecutar y podemos
definir las pruebas que cubran todos los posibles caminos del código.
- Según
el grado de automatización:
- Pruebas manuales: son las que se hacen normalmente al programar o las que ejecuta una persona con la documentación generada durante la codificación (P. ej.- comprobar cómo se visualiza el contenido de una página web en dos navegadores diferentes).
- Pruebas automáticas: se usa un
determinado software para sistematizar las pruebas y obtener los
resultados de las mismas (P. ej.- verificar un método de ordenación).
- En
función de qué se prueba:
- Pruebas unitarias: se aplican a un componente del software. Podemos considerar como componente (elemento indivisible) a una función, una clase, una librería, etc. En nuestro caso, generalmente hablaremos de una clase como componente de software.
- Pruebas de integración: consiste en construir el sistema a partir de los distintos componentes y probarlo con todos integrados. Estas pruebas deben realizarse progresivamente.
- Pruebas funcionales: sobre el sistema funcionando se comprueba que cumple con la especificación (normalmente a través de los casos de uso).
- Pruebas de rendimiento: los tres primeros tipos de pruebas de los que ya se ha hablado comprueban la eficacia del sistema. Las pruebas de rendimiento se basan en comprobar que el sistema puede soportar el volumen de carga definido en la especificación, es decir, hay que comprobar la eficiencia (P. ej.- Se ha montado una página web sobre un servidor y hay que probar qué capacidad tiene estado de aceptar peticiones).
- Pruebas de aceptación: son las únicas pruebas que son realizadas por los usuarios, todas las anteriores las lleva a cabo el equipo de desarrollo. Podemos distinguir entre dos pruebas:
- Pruebas alfa: las realiza
el usuario en presencia de personal de desarrollo del proyecto haciendo
uso de una máquina preparada para tal fin.
- Pruebas beta: las realiza
el usuario después de que el equipo de desarrollo les entregue una
versión casi definitiva del producto.
Otros conceptos relacionados con las
pruebas de software
- Completitud: nos da una idea del
grado de fiabilidad de las pruebas y por consiguiente la fiabilidad del
software. No es posible llegar al 100% puesto que nunca llegaremos a
realizar todas las pruebas posibles al software, puesto que las pruebas
tienen un coste (P. ej.- Bug del Excel).
- Depuración: ejecución controlada del software que nos permite corregir un
error (P. ej.- Usar el debugger de nuestra máquina).
- Pruebas de regresión: consiste en
volver a aplicar pruebas que se habían superado anteriormente (P. ej.-
Pruebas de integración).
Pruebas unitarias
automatizadas
¿Por qué pruebas
unitarias?
- Más exhaustivas: implica hacer pruebas por clase, función, etc., es decir, por la unidad mínima que se haya considerado.
- Probar trozos de código sin esperar al resto.
- Nos da más confianza para modificar código: se pierde el miedo a hacer modificaciones y volver inconsistente el sistema.
- Mejora la API: podemos darnos cuenta de fallos en la interfaz de la clase en pasos prematuros, evitando así el coste que supone una modificación en fases más avanzadas.
- Sirve como documentación de ejemplos de uso de la clase.
- Engancha cuando ves que tu código pasa todas las pruebas.
¿Qué probamos?
- Según el tipo de componente:
- Funciones individuales o métodos de objeto: probar las entradas y las salidas y comprobar que los valores obtenidos son los esperados.
- Clases de objetos:
- Hacer pruebas aisladas de operaciones
- Probar también las secuencias de las operaciones.
- Componentes
- Se tratan igual que una clase de objeto
- Hay que tener en cuenta si son distribuidos, en este caso es recomendable pasarle al componente pruebas de estrés.
- ¡No olvidar probar también el manejo de
errores!
- Según en qué aspecto nos centramos:
- Pruebas unitarias de código aislado:
- Independientes del resto del sistema.
- En la práctica esto no es posible en la mayoría de ocasiones, puesto que las clases interactúan entre sí. Para esto lo que se hace es sustituir los componentes por otros "de mentira" (mocks), para evitar así las dependencias.
- Pruebas unitarias de integración: se
prueba cada componente, pero dentro del todo de la aplicación, no como
elemento aislado
¿Cómo hacemos las
pruebas unitarias?
- Pruebas estructurales: son
Pruebas de caja blanca (no nos centraremos en estas).
- Pruebas de particiones: son pruebas de caja negra. Consisten en dividir las posibles entradas y salidas en conjuntos de características similares. Se identificarán los casos especiales y por ejemplo, los límites serán sometidos a pruebas siempre. Consejos a tener en cuenta a la hora de probar valores:
- Probar siempre los límites.
- Cuando tenemos listas, vectores, tablas:
- Probar pistas de un solo valor y listas
vacías.
- Probar siempre distintos tamaños.
- Comprobar primer elemento, el elemento
central y el último elemento.
- Pasar null en vez del
objeto.
¿Dónde ejecutamos
las pruebas unitarias?
En java podemos
usar JUnit para las pruebas unitarias y JMeter para pruebas de rendimiento.
Para otros lenguajes existen herramientas similares.
¿Cuándo implementamos
las pruebas unitarias?
- De forma paralela a la codificación (clase -
prueba).
- Antes de la codificación siguiendo un
desarrollo guiado por pruebas (punto siguiente).
Desarrollo guiado
por pruebas (TDD - Test-Driven Development)
Se basa en la filosofía de únicamente
escribir nuevo código cuando una prueba unitaria falle o para eliminar código
duplicado. (Por ejemplo: Probar la interfaz de login antes de codificar las
clases que interactúan con la BD).
(Se toman los módulos más importantes
que compondrán el software, se programan y se integran. Se prueba que funcionen
correctamente y entonces se cogen otros módulos y se comienza de nuevo el
proceso).
Desarrollo habitual:
Test-Driven Development:
Refactorizar: reorganizar, limpiar el código,
etc. sin alterar la funcionalidad de éste.
Programación ágil: esta metodología de trabajo consiste
en irse centrando en los requisitos del sistema por orden de importancia:
llevar a cabo las pruebas y la codificación partiendo de los requisitos más
exigidos por el cliente, presentándole éstos según se han ido implementando, y
a partir de ahí ir integrando requisitos en orden descendente de relevancia.
Ventajas del TDD:
- Comprensión.
- Documentación.
- Evitar sobreingeniería.
Conclusiones
- Nunca un producto software se ha terminado de
probar. Hay que establecer un límite dependiendo de la trascendencia,
costes, etc. del proyecto.
- La superación de las pruebas no implica que no
existan errores, sino que no se han detectado.
- Las pruebas del software no garantizan la
calidad de éste: las pruebas demuestran la calidad pero no la garantizan.
No hay comentarios:
Publicar un comentario