miércoles, 15 de febrero de 2012

Prueba de Software

Introducción a la prueba del software, sus objetivos, técnicas y relación con otras actividades del desarrollo de software.

¿Dónde estamos?

Antes de tratar la prueba de software, me parece necesario que acordemos que entendemos por software, como se construye, que entendemos por calidad del mismo y cual es nuestro contexto organizativo.

¿Qué es el software y cómo lo desarrollamos?

Software es el conjunto de instrucciones que controlan el funcionamiento de computadoras con programa almacenado. Antes, la funcionalidad estaba definida por engranajes o conexiones eléctricas. A partir del desarrollo de las computadoras con programas almacenados en la década de 1940 se pudo cambiar comportamiento de las mismas con sólo modificar el contenido de las memorias. Inicialmente el desarrollo de software se consideraba parte del desarrollo de la computadora, que correspondia a matemáticos, físicos, ingenieros eléctricos y electrónicos.
Con el pasar del tiempo, la complejidad del software creció hasta que empezó a ser complejo y costoso de desarrollar. Siendo una actividad joven, para entenderla y analizarla se intenta asimilar a otras actividades más maduras. A fines de la década de 1960 se empieza a llamar Ingeniería de Software a la disciplina. Se intentaba tomar, a partir de la analogía con las ingenierías, ideas para mejorar el desarrollo de software. Esta no es la única analogía que se ha utilizado para entender el desarrollo de software.

Analogías

Se han propuesto varias analogías, según las cuales el software es parecido a: la publicación de investigación académica, el resultado de un trabajo en equipo (música, teatro, cirugía, deportes, SWAT), un proceso de producción (línea de montaje), una creación artística (literatura). Las analogías pueden ser útiles, ya que nos permiten reusar el conocimiento e ideas de otras áreas, pero por otro lado nos pueden engañar, ya que nos enfocamos a las características comunes, minimizando las diferencias.
Planteo un muy breve resumen de las analogías, sólo para que luego lo usemos al discutir la visión de la calidad en el software.
  • Publicación de investigación académica: este es el modelo que origina el movimiento de software libre, según lo descripto por Richard Stallman [GNU]. En la investigación, todo resultado publicado es utilizable por otros, siempre que se cite la fuente. Esta analogía lleva a visión de la construcción del software como una continua mejora y extensión del trabajo de otros, y expuesto al escrutinio de cualquiera que le interese.
  • Música y teatro: el producto es una construcción colectiva y, aunque se base en un texto (partitura, obra de teatro), la interpretación produce un producto nuevo, cada función de teatro o cada recital es distinto. Se puede pensar que el equipo es en si mismo un producto del proceso de desarrollo [AustinLevin]. Esta analogía hace foco en la innovación, el espacio para la experimentación sin miedo al 'error'.
  • Deportes: la dinámica de los equipos deportivos y la motivación, en algunos aspectos similares a los de música y teatro, se asimila a los equipos de desarrollo de software. Aparecen la noción de entrenador (coach). Tiene en contra que la mayoría de los deportes son juegos competitivos, y el desarrollo de software no suele serlo [Cockburn].
  • S.W.A.T. / Cirugía: equipos con mucho entrenamiento, roles en general definidos, y objetivos claros y urgentes [Brooks], en el caso del equipo de cirugía, hay un rol de liderazgo muy fuerte. Se asemejan a los equipos de operaciones y mantenimiento de IT, aunque en el libro se utiliza como metáfora del desarrollo de software.
  • Proceso Manufactura: en la búsqueda de modelos exitosos, se toma la línea de montaje (tanto tradicional o taylorista como Lean Manufacturing[LarmanVodde]). ¿Cómo lograr que el desarrollo de software hacerse de esa manera? Tenemos que separar la parte creativa y novedosa, para que podamos optimizar la construcción.
  • Literatura: el software como una forma de comunicarse entre personas [Knulth] o las similitudes entre el proceso creativo de la escritura y el desarrollo de software.[Nachmanovitch]
  • Diseño de nuevos productos: el software diseñando como producto de consumo masivo, con la particularidad que tiene costo de duplicación prácticamente nulo (no tiene producción en el sentido de los bienen físicos) [TakeuchiNonaka].

Características y producto completo

El software se suele describir como intangible y maleable. Tiene costo de duplicación y distribución cercano a cero.
Sin embargo, el software es normalmente parte de un producto o servicio que incluye otras cosas.
Los casos obvios son los productos con software embebido, como celulares, lavarropas, aviones, etc.
Pero aún los productos que parecen ser exclusivamente software, para el usuario incluyen manuales, soporte posventa, capacitaciones , comunidad y otras aplicaciones que se relacionan, todo lo que llamamos el producto completo (Whole product [Moore]).
Si consideramos el producto completo, puede tener diferentes características. Por ejemplo, los cambios de VisualBasic 6 a VisualBasic.Net, de Python 2 a Python 3, o de IP4 a IP6 fueron mejoras en el software que tardaron en reflejarse en el producto completo: comunidad, desarrollo de terceros.

La calidad del software

Dependiendo de como entendamos el desarrollo de software (ver Analogías), se proponen distintas definiciones de la calidad, por ejemplo:
  • Cumplimiento de requerimientos: Se consideran los requerimientos implícitos y explícitos. Aplicado cuando se ve el desarrollo de software como un proceso de manufactura.
  • Apropiado al uso: ¿puede el usuario utilizar el producto en su entorno habitual? No cumplir con los requerimientos sin considerar la realidad. Los requerimientos en si mismos son vistos como parte del proceso de desarrollo, por lo que deberán ajustares si comprobamos que el producto por alguna razón no puede ser usado en el entorno del usuario.
  • Satisfacción del usuario: aunque es aplicable en cualquier caso, es muy usado la visión 'artística' del desarrollo del software (Literatura, Música y Teatro).

Los contextos de la prueba

La prueba está afectada por el contexto [Gabardini]. Las perspectivas que podemos utilizar para evaluar el contexto:
  • Impacto de los errores en el usuario final: afectamos muchas vidas humanas (ej. aviación), una vida (ej. radioterapia), grandes montos de dinero (ej. homebanking), montos de dinero menores, inconvenientes (ej. sistema de seguimiento de incidentes), diversión (ej. juegos).
  • Cultura de la organización: hay varias clasificaciones de cultura, por ejemplo [Schneider] Colaboración, Control, Competencia, Cultivo.
  • Objetivos: ¿cuándo se considera exitosa la prueba?. Métricas de algunos objetivos posibles son detectar defectos para corregirlos y mejorar la calidad, o sólo medir la calidad.
  • Metodología de desarrollo: Cascada, Iterativa Incremental, Ágil [ColussoGabardini].

QA, QC y Testing

Quality Assurance (Aseguramiento de la Calidad): ¿Cumplimos con los procesos que tenemos definidos? Los procesos definidos es la mejor manera que tenemos de hoy de hacer las cosas. Si no los seguimos, ¿por qué es?
Rol de QA: Dependiendo del estilo de las personas que lo realizan y de la forma en que se definen los procesos (por el equipo o desde fuera del equipo), puede ser visto como un rol policial o como un soporte al equipo. Está muy arraigado en el mercado como la cumbre del plan de carrera de alguien que trabaja en calidad de software. Es un rol que no es muy importante en los entornos de desarrollo ágil, ya que los procesos son definidos por los equipos, y son los equipos los principales interesados en cumplirlos. En estos entornos puede mantenerse la sigla (QA) debido al arraigo en el mercado, aunque con un sentido cambiado (Quality Assistant - Asistente de la Calidad) para enfatizar que los responsables de calidad son todos los miembros del equipo.
Quality Control (Control de Calidad): pruebas realizadas sobre el producto para determinar si cumple con los criterios definidos de aceptación. Aplicable en principio al producto terminado, aunque se extiende a productos intermedios.
Testing (Prueba): cualquier actividad de prueba del producto, en cualquier momento de su desarrollo. Por ejemplo se puede hacer las pruebas antes de construir el producto (TDD), haciendo que la calidad esté en el producto por construcción, algo que no es QC.
La diferencia entre QA y QC/Testing es que QA es sobre los procesos y QC/Testing sobre el producto.

Conceptos y terminología

Diseño y organización

  • Condiciones de prueba (Test condition): un atributo, característica o área de riesgo que se quiere probar. Se pueden encontrar como listas (checklist) de problemas comunes, o partiendo de los requerimientos. Por ejemplo: probar valores límites, en enteros uno antes del límite, el límite y uno después del límite, en el caso de dinero, diferencias de un centavo.
  • Casos de prueba (Test case): una descripción de una prueba particular (ejemplo). Contiene las pre-condiciones, los pasos a seguir y datos de entrada utilizados, y el resultado esperado (y postcondiciones). Varios casos de prueba pueden corresponder a una condición de prueba.
  • Grupo de pruebas (Ciclo de prueba o Test suite): agrupamiento de los casos de prueba según cierta característica que me permite organizar el diseño, la ejecución y reporte. Un caso de prueba puede estar en varios Grupos de Prueba. Por ejemplo, la prueba  de límites en la extracción de cuenta puede estar en el Grupo de pruebas de caja de ahorro, y en el Grupo de pruebas de regresión general.
  • Regresión: es la aparición de defectos en funcionalidad que ya había sido probada y estaba libre de errores. En el sentido más estricto se refiere a la reaparición de defectos que habían sido corregidos, pero se usa también, en un sentido más laxo, a la aparición de nuevos defectos en código ya probado.
  • Pruebas de regresión (Regression test): es la prueba orientada a encontrar regresiones. Las pruebas de regresión difieren de otras pruebas en que no esperan encontrar defectos, su tamaño se relaciona con el tamaño y complejidad total del producto (no del tamaño del último cambio hecho) por lo que son contínuamente crecientes (ver Código legado).
  • Particiones y clases de equivalencia: considerando la cobertura de entradas o de salidas, dado que las variables (parámetros o resultados) pueden tener gran cantidad de valores posibles, se acota la prueba identificando conjuntos de valores para los que el programa se comporta de la misma manera. Estos conjuntos se llaman clases de equivalencia, y se definen de manera de tener el espacio de valores de entrada y salida particionado. Se llama partición a una división que es completa (no queda nada sin probar) y sin superposiciones (no se prueba nada dos veces).

Resultados de la prueba

  • Bugs: algo anduvo mal en un software. No es un termino muy preciso, y puede tener alguno de los siguientes tres sentidos.
  • Falla: una situación en la que la aplicación exhibe un comportamiento no deseado. Ejemplo: al ingresar un par de valores, la aplicación termina con un mensaje de división por cero.
  • Defecto: comportamiento no deseado en la aplicación. Es la descripción de una clase de fallos. Ejemplo: en el caso anterior, luego de analizar los fallos descubrimos que la aplicación falla siempre que el par de valores que ingresamos sean iguales, ya que usa la diferencia entre los valores como denominador.
  • Error: la causa por la cual la aplicación tiene un comportamiento no deseado. Ejemplo: en el caso anterior no se está detectando que al tener el mismo valor habrá una división por cero. 

Calidad de la prueba

  • Cobertura: es una métrica sobre el grado de prueba que ha tenido el producto. Por ejemplo, una cobertura de lineas de código del 80% indica que un 20% de las líneas de código no han sido ejecutadas nunca durante la ejecución de los casos de prueba. Hay varios tipos de cobertura: de requerimientos, de código (que a su vez pueden ser de lineas, expresiones, camino y otros), de entradas, de salidas, de riesgos.
  • Código heredado o legado (Legacy code): código que es difícil de mantener y evolucionar. Desde el punto de vista de la prueba, una razón que define un código como legado es que las pruebas de regresión no estén automatizadas. Esto hace que las pruebas de regresión sean muy costosas (manuales) y esto lleva a que se desee minimizar los cambios, para realizar pocas pruebas y/o que las pruebas se realicen espaciadas en el tiempo, con lo que las regresiones quedan sin detectar durante mucho tiempo.
  • Eficiencia de la prueba: resultados obtenidos del esfuerzo dedicado a la prueba el producto, por ejemplo cuantas horas de prueba son necesarias para detectar y reportar un defecto.
  • Eficacia de la prueba: ¿se cumple el objetivo de la prueba?. Por ejemplo, porcentaje de defectos detectados vs defectos existentes.
  • Criterios de calidad de la prueba: ¿la prueba que estamos haciendo es buena? Algunas métricas que miden la calidad de la prueba son: porcentaje de detección de defectos (mutation testing), porcentajes de cobertura, tiempo de prueba para la detección de un defecto (esta métrica por sí sola no discrimina entre la eficiencia y efectividad de la prueba), cantidad de defectos detectados en producción (mide la calidad del proceso completo de desarrollo, indirectamente la calidad de las pruebas).

Modelos

Modelo V (V-Model): es la visualización del proceso de desarrollo de software entendido como una serie de traducciones desde el concepto hasta el código en la línea descendiente de la V, y la serie de pruebas correspondientes hasta la aceptación del producto por el usuario en la rama ascendente. Se puede interpretar como una secuencia temporal, y estaríamos en un proceso en cascada (waterfall, o como una clasificación de las actividades, que pueden ser hechas en diferentes momento del proyecto. La actividades son:
  • Requerimientos: obtener los requerimientos de los usuarios y otros involucrados, modelizar conceptualmente el negocio
  • Arquitectura: diseño de alto nivel, incluyendo decisiones de estructura, comportamiento, modularización y estilos.
  • Diseño detallado: diseño de componentes, sus interfaces y semántica.
  • Programación: programar cada uno de los componentes de la aplicación.
  • Prueba unitaria: validar que los componentes cumplan con los diseños detallados
  • Prueba de Integración: validar que los componentes se integren correctamente y presenten las características arquitecturales deseadas.
  • Prueba de Sistema: validar que el sistema cumpla con los requerimientos.
  • Prueba de Aceptación: validar que el producto sea aceptado por el usuario.
Matriz de la Prueba Ágil (Agile Testing Matrix o Cuadrantes de Brian Marick): esta matriz tiene dos dimensiones, cada una con dos valores, lo que da lugar a 4 clases de prueba. Esta clasificación es útil para planificar las pruebas y se usa en equipos de desarrollo ágil [CrispinGregory]. Las dimensiones son lenguaje (Tecnología, Negocio) y beneficiado (equipo, producto). No implica orden de importancia ni temporal:
  • Primer cuadrante (tecnogía y soporte al equipo): pruebas unitarias y de componentes, usualmente escritos en el mismo lenguaje que el programa. Tienen por objetivo servir de red de seguridad para el equipo, permiten desarrollar con la confianza que el programa cumple con el diseño, para ver si hacemos bien el producto. El diseño está descripto por las pruebas.
  • Segundo cuadrante (negocio y soporte al equipo): ejemplos, pruebas funcionales, story test (pruebas de la historias de usuario), prototipos y simulaciones. Están escritos en el lenguaje de negocio, deben ser entendidos (y a veces hechos) por los usuarios. Es una red de seguridad para ver que estamos haciendo el producto correcto.
  • Tercer cuadrante (negocio y mejora al producto): pruebas exploratorias, escenarios, pruebas de usabilidad, pruebas de aceptación, procesos de pruebas Alpha y Beta. Permite detectar mejoras al producto, y tomar la decisión sobre si el producto está listo para pasar a producción.
  • Cuarto cuadrante (tecnología y mejora al producto): pruebas de rendimiento, carga, estrés, seguridad (pruebas ...ility). Permite detectar mejoras para el producto, requieren herramientas y profundo conocimiento técnico de todas las tecnologías involucradas y las formas de uso del producto.

¿Cuándo probamos?

La detección de defectos en forma tardía tiene varios efectos negativos: se pierde la oportunidad de aprender del error y por lo tanto se repite; se desarrolla alrededor de los errores, por lo que luego se hace más difícil corregir; y la acumulación de defectos dificulta poner foco en lo importante.

¿Cómo probamos?

Actividades

El testing se puede dividir en distintas actividades. Estas actividades pueden ser hechas secuencialmente o en paralelo, por roles específicos o distribuidas en todo el equipo.
  • Plan: decidir qué se va a probar (alcance), quién prueba, cuándo se prueba, cómo se prueba (técnicas, herramientas, estrategias), cuánto se prueba (criterio de calidad de la prueba), a quien reportamos el estado del producto, y en qué formato. Se toman los objetivos del negocio, se identifican los riesgos que los afectan y las características de arquitactura que se deben medir.
  • Diseño: partiendo del lo planeado, se diseñan las herramientas y pruebas que se usarán, por ejemplo se definen cuantas pruebas se necesitan analizando las condiciones de prueba.
  • Construcción: escribir los casos de prueba, documentos para prueba manual o programas para prueba automática.
  • Ejecución: ejecución de los casos de prueba en los ambientes definidos. Se ejecutan conjuntos de casos de pruebapor ejemplo, las pruebas de regresión.
  • Reporte: registrar el resultado de la ejecución: casos ejecutados, casos bloqueados (no pudieron ejecutarse), defectos encontrados, sugerencias de nuevas pruebas. Resumir los resultados para ser informados a los interesados en el producto.
  • Administración: seguimiento de requerimiento, casos de pruebas y defectos. Hacer seguimiento significa que se mantienen actualizados (agregar, actualizar y quitar) y relacionados unos con otros, se prioriza el trabajo sobre los mismos y decide cuando y cuales deben ejecutarse.
  • Métricas y Mejora: medir el resultado del trabajo (producto) y la forma de trabajo (proceso), para identificar oportunidades de mejora. Algunos ejemplos de métricas son: cantidad de defectos detectados en producción, tiempo que lleva detectar defectos, porcentaje de build a los que se les detectan defectos por medio de las pruebas automáticas, cuanto tarda la prueba de regresión.

Tipos y estrategias de prueba

  • Exploratorio: prueba no guionada, ni repetitiva. Suele ser realizada con una misión definida (por ejemplo, probar la usabilidad o reproducir un defecto), con tiempo limitado (timeboxed), y se realiza de modo simultáneo la planificación, diseño y ejecución de las pruebas, en ciclos cortos (minutos) que permiten adaptar el nuevo ciclo a los resultados obtenidos en el anterior, en un proceso de aprendizaje. Puede tener soporte de herramientas, pero no puede ser automatizado. Finaliza con un reporte de la prueba en el que se describe las hipótesis, las pruebas realizadas, los resultados de las mismas, y los posibles pasos a seguir.
  • Test-Driven Development (TDD): una forma de diseño y programación, que se basa en declarar el diseño en la forma de ejemplos ejecutables (pruebas) del uso del componente, antes de programar el componente. El ciclo de TDD consiste en: escribir las pruebas, ver que fallen (no está el código correspondiente), escribir el código mínimo para lograr que la prueba pase, ver ver que las pruebas pasen, y luego revisar el código (del componente y de las pruebas) para mejorarlo (también llamado refactoring). Esta técnica se origina en Extreme Programming, y tiene mucha relación con otras como Pair Programming, Simple Design, Coding Standard. No es una técnica de prueba en sí misma, pero genera como subproducto un conjunto de pruebas automatizadas con alta cobertura de código, lo que implica que el software desarrollado de esta manera suele tener niveles de calidad muy buenos.
  • Prueba Automatizada: estas pruebas son construidas completamente antes de la ejecución de las mismas, por lo que no se requiere intervención humana durante la ejecución. Esto permite que se realicen frecuente y rápidamente.
  • Aceptación: pruebas realizada por el usuario (o cliente o sus representantes) que definen si el producto se ajusta a las necesidades y puede ser aceptado. Según la relación entre el usuario y el equipo de desarrollo puede ser que la aceptación se refiera sólo al cumplimiento de las necesidades explicitadas o sea más amplio.
  • Funcional: pruebas desde el punto de vista de la funcionalidad, y no sobre temas como confiabilidad, mantenibilidad, usabilidad, seguridad. Dado que la definición de funcionalidad puede ser ambigua (por ejemplo se pude considerar que no tiene sentido distinguir entre requerimientos funcionales y no funcionales), en ocaciones se usa este término con el mismo sentido que prueba de sistema.
  • Integración: pruebas orientadas a las interacciones entre los distintos componentes que componen el producto. Se buscan que se comuníquen correctamente tanto desde el punto de vista sintáctico como semántico.
  • Sistemas: pruebas de punta a punta, considerando no sólo el producto que el equipo está desarrollando, sino también otras productos (de software o no), procesos y personas involucradas en la solución a las necesidades del usuario.
  • Otros tipos o estrategias: fuzzing, combinatoria, guiada por riesgos, Behavior-driven development (DBB), caja negra, caja blanca, pruebas de regresión, pruebas formales.

Bibliografía

[AustinLevin] Artful Making, Rob Austin y Lee Davin.
[Brooks] The Mythical Man-Month, Fred Brooks.
[Cockburn] Alistair Cockburn, obtenido 2011-05-16 http://alistair.cockburn.us/Software+development+as+a+cooperative+game
[ColussoGabardini] Desarrollo Ágil de Software, Ricardo Colusso & Juan Gabardini. http://knol.google.com/k/desarrollo-ágil-de-software
[CrispinGregory] Agile Testing, Lisa Crispin & Janet Gregory.
[Gabardini] ¿Exite la mejor forma de probar?, Juan Gabardini. blog, video, presentación: http://softwareagil.blogspot.com/2011/01/la-mejor-manera-de-probar-en-agilesbsas.html
[GNU] "The GNU Project (essay)". obtenido 2011-05-16 http://www.gnu.org/gnu/the-gnu-project.html
[Knulth] Literate Programming, Donald Knuth.
[Moore] Crossing the chasm, Geoffrey Moore.
[Nachmanovitch] Free Play, Stephen Nachmanovitch (comentado en http://bit.ly/mdnKOe)
[LarmanVodde] Lean Primer; Larman & Vodde. http://www.leanprimer.com/downloads/lean_primer.pdf
[Schneider] The Reengineering Alternative, William E. Schneider.
[TakeuchiNonaka] The new new product development game, Takeuchi & Nonaka, HBR.


Que falta en este documento

  • ¿Quienes probamos?
  • ¿Por qué probamos?
  • Referencia al checklist de TestObsessed
  • Cambiar referencias al formato knol
  • Gráficos: contexto de la prueba, pirámide de la prueba
  • Cuadro comparativo QA/QC/Testing
  • Definiciones de Validación y Verificación, smoke test (build validation test), caja blanca y negra.
Publicar un comentario en la entrada