TESTING DE SOFTWARE
La
Prueba de Software se encuentra en el contexto de Aseguramiento de Calidad (bajo el
contexto de SCM), pero cuando hablamos de pruebas de software no nos referimos a
control de calidad de proceso ni a control de calidad de producto.
Testing de Software
Es un proceso destructivo, porque su objetivo es encontrar los defectos (no es
asegurar que el software funcione) ya que nosotros asumimos que en el software hay
defectos (en el código).
Decimos que es un proceso destructivo porque implica ir con una actitud negativa para
demostrar que algo es incorrecto.
Un Test es exitoso cuando encuentra la mayor cantidad de defectos.
Podemos decir con esto que un desarrollo exitoso nos conduce a un test no exitoso.
(juego de palabras).
Recordar: es Testing no tiene nada que ver con el asegurar de que el producto
de software que se construye funciona.
Mundialmente dentro del costo de un software confiable, el Testing se lleva entre un
30% y 50% del costo, para lograr que el software sea confiable.
Error
Se descubre en la misma etapa en la que se está trabajando actualmente.
Ejemplo:
Se está escribiendo código y en esa misma etapa se hace una revisión de código y
encontramos un problema.
Existen técnicas de revisión e inspección.
Claramente es mucho mejor encontrar errores que defectos en el proyecto de
desarrollo de software.
Defecto
Implican que el error que se tenía y no se detectó, se traslada a una etapa siguiente.
Con esto podemos aclarar que en el Testing solo encontramos defectos. Porque
estamos encontrando inconvenientes o cosas mal hechas que se hicieron en la etapa
de Implementación (etapa anterior al Testing)
Hay dos aspectos importantes para decidir qué hacer con los defectos:
Severidad: tiene que ver con la gravedad del defecto que se encontró.
1. Bloqueante: debido a ese defecto no se puede seguir con el caso de prueba,
bloquea dejándonos en un determinado lugar sin poder avanzar.
2. Critico: es un defecto que compromete la ejecución del caso de prueba en
cuanto a su resultado, por lo que los resultados obtenidos no son los
esperados.
3. Mayor: sigue siendo un defecto grave.
4. Menor:
5. Cosmético: es un defecto más simple, comúnmente relacionado con la sintaxis,
ortografía o visualización.
Esta es una clasificación tentativa para imaginar cómo se pueden clasificar los defectos
que se encuentran.
Prioridad: está relacionada con la urgencia que se tiene para resolver ese
defecto.
1. Urgencia
2. Alta
3. Media
4. Baja
Los casos más importantes de severidad no están relacionados con los casos
más importantes de prioridad.
Es decir, un defecto de severidad bloqueante puede ser de baja prioridad. Depende
comúnmente del contexto para el cual se desarrolla el software.
Al no manejarse de la misma manera es importante siempre tener en cuenta los dos
aspectos.
Niveles de Prueba
Es un aspecto importante a la hora de decidir qué pruebas son las que se van a llevar a
cabo.
Están relacionados a que cuando se habla de subir de nivel, por así decirlo es como
subir escalones abarcando más cosas a medida que se sube de nivel.
Implica que dentro de los niveles se van a tener:
1. Pruebas Unitarias
Son aquellas pruebas en las que probamos un componente individual. Probamos algo
acotado en relación al desarrollo de lo que se está construyendo.
Este tipo de pruebas a diferencia de las demás, son ejecutadas normalmente por los
mismos desarrolladores, es decir, la misma persona que está construyendo, sobre todo
si el Testing está automatizado.
Esta dentro de las pruebas más fáciles de automatizar, son las que se hacen con
respecto a componentes o a aspectos puntuales y aislados del código que se está
construyendo.
2. Pruebas de Integración
Implica integrar los componentes que se probaron en la Prueba Unitaria y pasaron, a
partir de allí se los integra para ver como funcionan cuando trabajan juntos.
Son ejecutadas por aquellas personas que tienen el rol de Tester (ocupan ese rol
dentro del equipo de trabajo).
3. Pruebas de Sistema
Son pruebas más amplias, donde no solo se prueba la integración de componentes,
sino que también se prueba el sistema en toda su escala (por decirlo de alguna
manera)
Son ejecutadas por aquellas personas que tienen el rol de Tester (ocupan ese rol
dentro del equipo de trabajo).
4. Pruebas de Aceptación
Así como las Pruebas Unitarias responden a una regla que establece que no se
presenta en el resto de los niveles de prueba, que es que al probar componentes
individuales y de manera independiente normalmente son ejecutadas por el mismo
desarrollador.
Las pruebas de aceptación son ejecutadas muchas veces por el usuario final / cliente.
Tener en cuenta ..
En las Pruebas Unitarias, casi podríamos decir, que lo que se encuentran son errores
más que defectos. Debido a que en el mismo momento en el que el desarrollador
construye el componente es cuando lo prueba, entonces al hacerse todo como parte
del mismo proceso casi está al límite de si es un error o un proceso.
Por el contrario cuando se habla de Testing de Integración, en ese caso ya se esta
buscando verificar que las partes de un sistema que funcionan bien de manera aislada,
también funcionen bien cuando están trabajando en conjunto.
Para poder pasar a las Pruebas de Integración y asegurarnos de que esos componentes
que funcionaban bien en las Pruebas Unitarias, funcionen bien cuando se integran. Esa
integración normalmente se hace de manera incremental (no se juntan los
componentes de una sola vez) para irlos sumando y ver como se conectan entre sí.
Todo lo que sea crítico y más importante para el negocio debe ser integrado y
probado lo antes posible.
Se pueden probar a su vez funcionalidades concretas, relacionadas con la integración
de componentes.
A diferencia con la Prueba de Sistema en donde si probamos la aplicación funcionando
como un todo, no nos concentramos solamente en los componentes que se integran,
si no que busca asegurarse de que el sistema en su totalidad opere de manera
satisfactoria.
También comienzan a impactar pruebas que están relacionadas a requerimientos no
funcionales (como aspectos de la performance, seguridad e integridad de datos). Para
poder hacer esto se debe lograr que el entorno de prueba sea lo más parecido posible
al entorno de producción.
El Testing de Aceptación es ejecutada por el usuario final / cliente, a diferencia de las
otras pruebas donde el objetivo es encontrar defectos. El objetivo de las pruebas de
aceptación es establecer confianza en el sistema más que encontrar defectos.
(teniendo en cuenta de que las realiza el usuario, también puede encontrar defectos)
Debemos tener un ambiente lo más posible al entorno de producción, las famosas
versiones beta son sometidas al Testing de Aceptación.
Ambientes para la Construcción del Software
Son los ambientes que tenemos en el contexto del desarrollo de software, es lo mismo
que hablar de entorno (son sinónimos)
Son lugares donde se trabaja para la construcción del software.
1. Desarrollo : lugar donde los desarrolladores escriben código (se pueden realizar
Pruebas Unitarias)
2. Prueba: pruebas de integración, en general tenemos un entorno parecido al de
producción pero no tiene las mismas características. (también se pueden hacer
Pruebas Unitarias)
3. Pre – Producción: se realizan las pruebas de sistemas o pruebas de aceptación.
4. Producción: es el entorno donde el software está en operación.
A veces se puede usar para pruebas de aceptación si el software por ejemplo no está
en operación. Como cuando el software es nuevo.
Tienen ciertas características que hacen que funcione de una manera adecuada en la
organización, es decir, que cumpla con requisitos de performance, aquellos
relacionados con la concurrencia, aspectos de seguridad y redundancia.
Es caro tener ambientes iguales a los de producción, por lo que usamos ambientes
parecidos para aquellas pruebas que lo necesitan.
Caso de Prueba
Tiene que ver con un conjunto de condiciones o variables que nos permiten
determinar si el software esta funcionando correctamente o no.
En donde tenemos definido en el CP que acciones vamos a ejecutar (pasos),
concretamente establecemos que variables vamos a usar y que datos va a tener a la
hora de realizar cada uno de los pasos.
Ejemplo: Iniciar Sesión
Si el usuario que se ingresa no existe el resultado de la ejecución del caso de prueba
esperado es un mensaje de error.
Para saber si el software está funcionando correctamente o no se debe escribir que
usuario vamos a usar, que contraseña se va a ingresar y cuál es el resultado esperado.
El Caso de Prueba tiene que ver con ejecutar una serie de pasos / acciones en
una determinada funcionalidad, determinando concretamente con que valores
se va a hacer la ejecución para ver si el software da el resultado esperado o no.
Además de ir indicando concretamente las acciones a ejecutar, debe decir
concretamente con que valores hay que ejecutarlo.
Si el mismo esta bien definido es más fácil de reproducir defectos, debido a que si por
ejemplo en lugar de iniciar primero el usuario y después la contraseña, dejamos el
usuario y no ingresamos la contraseña. Si hay algún defecto en esa ejecución podemos
volver a ejecutar el caso de prueba de la misma manera para reproducir el mismo
defecto.
Si el defecto no se puede reproducir, el defecto no se puede resolver. Es algo
fundamental para que el éxito del Testing nos depare luego y a través de la corrección
en un software confiable.
Estrategias de Prueba
Dentro de los Casos de Prueba y cuando debemos identificarlos, se presenta el
inconveniente de que no podemos definir / identificar casos de prueba de manera
infinita o que surgen en función de lo que se nos va ocurriendo.
Debemos tener un mecanismo para lograr definir la menor cantidad de Casos de
Prueba, ya que cuanto más Casos de Prueba tenemos, más debemos ejecutar y poner
más esfuerzo.
Tratar de identificar la menor cantidad de Casos de Prueba que permitan cubrir
el Testing del software de la manera más completa posible.
Para ellos usamos estrategias de prueba con el objetivo de poder definir la menor
cantidad de casos de prueba logrando una cobertura del Testing de manera completa.
El Testing exhaustivo de todas las opciones que nos presenta el software no es viable.
Para esto conducimos el esfuerzo a utilizar para cubrir el Testing de manera completa,
para ello definimos de cierta manera los casos de prueba.
Uno de los aspectos está relacionado a que en los límites es normal donde se
concentran los defectos, por lo que cuando definimos Casos de Prueba tratamos de
apuntar a esos lugares donde se encuentran normalmente.
“Los Bugs se esconden en las esquinas y se congregan en los límites” .
Probamos en los límites de lo tolerable.
Derivación de Casos de Prueba
Se pueden derivar desde distintos lugares.
Cuanto más documentación tengamos, más fácil es hacer los casos de prueba. Cuando
menos especificación tengamos debemos escribir con más detalle los casos de prueba.
Es decir, si nosotros tenemos una especificación de requerimientos detallada y con
casos de uso más precisos, seguramente la derivación de casos de prueba es casi
automática.
De lo contrario si se está escrito de manera general y poco preciso cuando se llegue a
los casos de prueba debemos especificar lo que no se hizo antes.
Desde todos estos lugares se pueden derivar casos de prueba.
Existe una metodología de Especificación de Requerimientos, donde a partir de la
definición de los casos de prueba en lugar de especificar los requerimientos escribimos
los casos de prueba y usamos los mismos como especificación de requerimientos y
casos de prueba.
Conclusiones sobre la Generación de Casos de Prueba
Vamos a utilizar distintas técnicas (Estrategia de Caja Blanca y Caja Negra)
Las técnicas atacan distintos problemas
Lo mejor es combinar varias de estas técnicas para complementar las ventajas
de cada una.
Depende del código a testear.
Tener en cuenta la conjetura de defectos.
Sin requerimientos todo es mucho más difícil.
Ser sistemático y documentar las suposiciones sobre el comportamiento o el
modelo de fallas.
Condiciones de Prueba
Tienen que ver con el contexto del sistema que debemos tener en cuenta para poder
hacer la prueba y darle contexto.
Son importantes y tienen que ver con las características de la entrada.
Es algo que se enuncia antes de que se defina el Caso de Prueba.
Es la reacción esperada de un sistema frente a un estimulo en particular, este
estimulo está constituido por las distintas entradas.
Una condición de prueba debe ser probada por al menos un caso de prueba.
Estrategias
También se las denomina métodos.
El objetivo es tratar de definir o abarcar la mayor cantidad de cobertura con las
pruebas con el menor esfuerzo.
Las estrategias complementarias buscan abarcar la mayor cantidad de software
posible.
1. Caja Negra.
Se llama así porque en el caso de prueba definimos cuales van a ser las entradas y el
resultado esperado relacionado a como se comporta el sistema de acuerdo a las
entradas.
Como llega al resultado esperado o que hay en el medio NO lo sabemos.
Frente a determinadas entradas esperamos obtener determinadas salidas, si las
obtenemos el caso de prueba pasa y de lo contrario el caso de prueba falla.
Pueden dividirse en dos:
Basados en Especificaciones:
Partición de Equivalencia
Análisis de Valores Límites
Basado en la Experiencia: es el Testing que hace el Tester experimentado que
de alguna forma no se sabe porque sabe a donde ir y como ir para buscar el
defecto.
No hay nada establecido de ante mano, solo de acuerdo a su experiencia sabe
dónde es más común que se encuentren defectos.
2. Caja Blanca
Mira dentro del código revisando la estructura del mismo, para ver si hay algún lugar
en el que el sistema dada la prueba que se va a realizar de un resultado que no es el
esperado.
Vemos la estructura interna del software o de un componente del software.
Métodos:
Cobertura de enunciados o caminos básicos.
Cobertura de sentencias.
Cobertura de decisión.
Cobertura de condición.
Cobertura de decisión / condición.
Cobertura múltiple.
Ciclo de Test
Un ciclo implica tener un conjunto de casos de prueba, que son los que se van a
ejecutar, y la ejecución de todos los casos de prueba en una version del sistema
aprobada.
Es decir, se ejecutan todos los casos de prueba (terminando el ciclo 1 de Testing) y
luego vemos los casos de prueba que fallaron corrigiendo los defectos y realizamos
otros ciclo probándolos en la nueva version. Y así hasta donde llegamos a cumplir el
criterio de aceptación que se definió para el Testing.
Con el cliente se debe definir el momento en el que se deja de probar, ya que es
imposible probar hasta que no hayan defectos.
Luego de ejecutar los determinados ciclos de prueba o si ya no tenemos defectos
bloqueantes o críticos.
Regresión
Esta asociado a que la teoría establece que, al corregir un defecto normalmente se
introducen otros dos o tres defectos más como producto de esa corrección.
Es decir, no alcanza con solo probar el en ciclo de Testing los casos de prueba que
detectaban defectos. Tener en cuenta la introducción de nuevos defectos, por lo que
realizamos una nueva verificación total de la nueva version asegurando no introducir
nuevos defectos al intentar solucionar otros.
Se debe tener en cuenta la severidad y prioridad de los mismos.
Proceso de Pruebas
Es un proceso definido, que se basa en:
1- Planificación:
Parte más estratégica, en la que se arma el plan de prueba (contexto proceso
tradicional)
2- Identificación:
3- Especificación:
Se basan es escribir y definir los casos de prueba.
4- Ejecución:
Puede ser o no automatizada (manual, automatizada o ser una combinación de ambas)
5- Análisis de Fallas:
Chequeamos que el resultado obtenido de la ejecución de los casos de prueba es el
resultado esperado.
Si no es el resultado esperado se realiza en análisis de fallas y luego la corrección, que
se realizan la cantidad de veces necesarias hasta cumplir con el criterio de aceptación
que es el que determina el fin de las pruebas.
6- Fin de las Pruebas
Ejemplo Etapas / Entregables de Testing
Verificación
¿Estamos construyendo el sistema correctamente?
Apunta a evaluar si estamos construyendo el sistema correctamente.
Evaluamos si construimos el sistema libre de defectos, por eso se dice el sistema
correctamente, apuntamos a no tener defectos.
Validación
¿estamos construyendo el sistema correcto?
Apunta a verificar si construimos el sistema correcto. Cuando hablamos de sistema
correcto hablamos de comparar lo que nosotros construimos con lo que nuestro
cliente quiere.
Porque el sistema se corresponde con los requerimientos y estos se corresponden con
lo que el cliente quiere.
Testing en el Ciclo de Vida del Software
uno de los conceptos importantes tiene que ver con lograr involucrar las actividades de
Testing lo más temprano posible.
¿En qué momento podemos empezar a trabajar con las actividades de Testing?
Desde el principio, ya que teniendo los requisitos podemos comenzar a definir los
casos de prueba. Es decir, no necesitamos escribir ni una línea de código para
comenzar a trabajar en el Testing.
Nos puede servir esto para incluso darnos cuenta de si no omitimos algo en la User
Story, puede ocurrir que haya cosas que faltan definir o aclarar.
Dar visibilidad de manera temprana al equipo, de como se va a probar el
producto.
Disminuir los costos de correcciones de defectos.
Romper Mitos
No se empieza el Testing apenas se termina de escribir el código.
No es probar que el software funciona (su objetivo es encontrar defectos)
El Tester no es el enemigo del programador.
Si bien tienen objetivos contrapuestos, el Tester no hace más que visibilizar lo que
realmente está ocurriendo en el software, ya que asumimos que cuando construimos
software los defectos existen.
No es calidad de producto. (no asegura ni la calidad del producto ni la del
proceso) (solo nos ayuda a que el software sea confiable)
¿Cuánto Testing es suficiente?
El Testing exhaustivo no es viable.
Para saber cuánto Testing es suficiente, primero depende de una evaluación del nivel
de riesgo y de los costos asociados al proyecto.
Por otro lado debemos también tener en cuenta los criterios de aceptación que vamos
a acordar con el cliente. Y nos ayuda a determinar cuando el Testing fue completado.
El criterio de aceptación lo definimos de acuerdo a por ejemplo no encontrar más
defectos bloqueantes ni críticos, o que el porcentaje de test corrido sin falla alcance
cierto porcentaje. O dedicamos tal costo al Testing y una vez consumidas esas horas el
Testing finaliza.
Ejemplo:
Principios del Testing
Muestra presencia de defecto.
Exhaustivo es imposible.
Testing temprano.
Agrupamiento de defectos.
Paradoja del Pesticida:
Indica que cuando ejecutamos muchas veces los mismos casos de prueba, ni hablar si
los automatizamos, eso puede hacer que los casos prueba se ejecuten sin fallas pero
que en realidad las fallas o defectos en el software queden ocultos. Los defectos no se
vean porque siempre estamos ejecutando los mismos casos de prueba y de la misma
manera.
Dependiente del contexto.
Falacia de la ausencia de errores.
Un programador debería evitar probar su propio código.
(a excepción de las pruebas unitarias)
Una unidad de programación no debería probar sus propios desarrollos.
Examinar el software para probar que no hace lo que se supone que debería
hacer, y ver que hace lo que no se supone que debería hacer.
Es un aspecto importante relacionado con la actitud negativa con la que debemos
llevar a cabo el Testing, tiene que ver evaluar qué pasa si yo quiero hacer algo con el
software que no debería hacer.
Es importante porque no solo vamos a probar que el software haga lo que debe hacer,
sino que también se debe buscar ver que pasa si queremos hacer algo que no se
debería poder.
Implica no pensar que el Tester solo critica el trabajo del programador, porque la
asunción de los defectos en el software es algo obvio y lógico.
Se debe cambiar esta mentalidad acerca del Tester y acerca de la planificación del
Testing suponiendo que no vamos a encontrar el defecto. Esto no es viable.
No planificar el esfuerzo de Testing sobre la suposición de que no se van a
encontrar defectos.
Tipos de Pruebas
Smoke Test
Es un tipo de prueba que se hace cuando tenemos normalmente la primera version del
producto, se basa en realizar una corrida rápida sobre todo el software
Se dice que es rápido porque no se prueban escenarios alternativos, ni casos de
prueba rebuscados. Se realiza en términos generales viendo que no haya ninguna falla
catastrófica.
No es lo mismo que el Saninty Test, este asegura que se corren todos los test
asegurando que las funcionalidad básicas no tienen fallas críticas. El Smoke Test es más
superficial.
Testing Funcional
Se basa en ejecutar las pruebas de una manera relacionada a los requerimientos del
software. Vemos si se cumple con lo que está especificado en los procesos de negocio
o requerimientos.
Es el tipo de prueba más fácil, debido a que si los requerimientos están bien
planteados el Caso de Prueba deriva automáticamente de esos requerimientos.
Testing No Funcional
Son pruebas que no tienen que ver con “que hace” el sistema, sino con “como lo
hace”.
Se tiene especial importancia que los ambientes de prueba sean lo más parecido
posible a los ambientes de producción. Porque si se debe probar carga, estrés,
portabilidad, fiabilidad, necesitamos que el entorno en el que estamos trabajando sea
lo más parecido posible al entorno de producción.
Prueba de Interfaz de Usuario
Prueba de Performance
Podemos medir el tiempo de respuesta y concurrencia. Están relacionadas a los
requerimientos no funcionales.
Prueba de Configuración
Verificamos en cierta configuración como trabaja el sistema, para que el software
funcione correctamente .
TDD
Diseño conducido por casos de prueba, donde se escribe el código a partir del
desarrollo de casos de prueba.
Es una técnica avanzada que implica:
Escribir las pruebas primero, es decir, antes de escribir una línea de código
pienso primero que es lo que voy a probar cuando escribo esa línea de código
necesaria para que ese caso de prueba se ejecute de manera exitosa. (se
escribe el Testing automático que se va a hacer).
En general se hablan de pruebas unitarias de los componentes, son las que
comúnmente se automatizan.
Re Factory: implica que muchas veces cuando vamos escribiendo el código,
luego lo tiramos porque lo escribimos de nuevo mejorando aspectos para que
el software pase.
El “corazón” de TDD está relacionado con que primero elegimos el requerimiento que
se quiere probar, en base a esto escribimos la prueba (si escribimos una prueba
automatizada y no hay código, la misma va a fallar porque el requerimiento no está
implementado) y a partir de allí se escribe la implementación de tal manera que el test
pase.
Lo más importante no es escribir el código de la mejor manera necesariamente, lo
importante es que el test no falle más. Es decir, que esas líneas de código de esas
pruebas automatizadas que se construyen pasen.
Una vez que se logró que la prueba funcione comenzamos con la REFACTOR para dejar
el código “limpio”, esa refactorización implica escribir cosas de nuevo y luego volver a
ejecutar las pruebas para asegurarnos que siga pasando.
Si llegara a fallar la prueba, este proceso se repite hasta que el caso de prueba se
ejecute de manera exitosa y se un código limpio.
Solo se enfoca en el análisis funcional.
La mayoría de las veces los requerimientos no funcionales van más allá de aspectos
relacionados con el código, normalmente tienen que ver con el ambiente, las
condiciones en las que se ejecuta el software, equipamiento.