Pruebas de software
Caja blanca y caja negra, los cuatro niveles de prueba, las estrategias de integración, las pruebas de regresión, alfa y beta, las no funcionales y las herramientas más citadas.
Caja blanca y caja negra
La primera clasificación de las pruebas atiende a cuánto se conoce del interior de lo que se prueba. En la prueba de caja blanca se conoce el código y el detalle del algoritmo, e interesa lo que ocurre dentro: qué caminos recorre la ejecución y si todos ellos se han ejercitado. En la prueba de caja negra el interior no se mira: solo se comprueba que, para unas entradas dadas, salgan las salidas esperadas por la interfaz.
| Aspecto | Caja blanca | Caja negra |
|---|---|---|
| Qué se conoce | El código y la estructura interna | Solo la especificación: entradas y salidas |
| Qué se busca | Que se recorran todos los caminos, ramas y condiciones | Que el comportamiento observable sea el esperado |
| Quién suele hacerlas | El propio desarrollador | Un probador o el usuario, sin ver el código |
| También llamada | Estructural o de cristal | Funcional o de comportamiento |
Las técnicas típicas de caja blanca son la prueba de flujo de control, que sigue el orden en que se ejecutan las sentencias; la prueba de bifurcación o de decisión, que exige que cada condición se evalúe al menos una vez a verdadero y una vez a falso; y la prueba del camino básico, que calcula el número mínimo de caminos independientes que hay que recorrer para cubrir el grafo del programa.
- Cobertura de sentencias: que cada línea se ejecute al menos una vez. Es la más débil.
- Cobertura de decisiones o de ramas: que cada bifurcación se tome por sus dos salidas.
- Cobertura de condiciones: que cada condición simple dentro de una decisión compuesta se pruebe a verdadero y a falso.
- Camino básico: el número de caminos independientes coincide con la complejidad ciclomática de McCabe, que se calcula como el número de decisiones más uno.
- Clases de equivalencia (caja negra): se agrupan las entradas en conjuntos que el programa debería tratar igual y se prueba un representante de cada uno.
- Análisis de valores límite (caja negra): se prueban los extremos de cada clase, porque es donde se concentran los errores de comparación.
Caja blanca y caja negra no son excluyentes ni rivales: se complementan. La caja blanca puede recorrer todos los caminos de un algoritmo equivocado, y la caja negra puede dar por bueno un programa con código muerto que nunca se ejecutó.
Para el examen
Caja blanca: mira el código y sus caminos
Caja negra: solo entradas y salidas
Relación: no son rivales: se complementan
Los niveles de prueba
La segunda clasificación atiende a qué tamaño de pieza se prueba y en qué momento. Se recorre de dentro hacia fuera: primero cada componente por separado, luego las piezas conectadas entre sí, luego el sistema completo y por último el sistema en manos de quien lo va a usar.
| Nivel | Qué se prueba | Quién lo hace |
|---|---|---|
| Unitarias | Cada componente de forma individual y aislada del resto | El desarrollador, normalmente automatizadas |
| Integración | El ensamblaje entre componentes: que se entienden entre ellos | El equipo de desarrollo |
| Sistema | El sistema completo y las interfaces entre subsistemas, en un entorno parecido al real | Un equipo de pruebas independiente |
| Aceptación | Que el sistema hace lo que el usuario espera, desde su punto de vista funcional | El usuario o el cliente, que firma la aceptación |
Los cuatro niveles, en orden, son unitarias, integración, sistema y aceptación. La distinción que más falla: las unitarias aíslan una pieza y las de integración comprueban precisamente lo que ocurre entre dos piezas.
Métrica 3 añade a esta escalera un nivel más, las pruebas de implantación, que se hacen ya sobre el sistema integrado de hardware y software en su entorno real de operación, comprobando que funciona con la infraestructura, los datos y las comunicaciones de verdad. Van entre las de sistema y las de aceptación.
Para el examen
Los cuatro, en orden: unitarias, integración, sistema y aceptación
Unitarias: aíslan una pieza
Integración: comprueban lo que ocurre entre dos
Estrategias de integración
Cuando llega el momento de juntar los componentes hay que decidir en qué orden se ensamblan. La primera decisión es si se hace poco a poco o todo de golpe.
| Estrategia | En qué consiste | Qué hace falta |
|---|---|---|
| Incremental descendente (top-down) | Se empieza por los módulos de más alto nivel y se van añadiendo los de abajo | Módulos falsos que simulen a los inferiores todavía no escritos (stubs) |
| Incremental ascendente (bottom-up) | Se empieza por los módulos de más bajo nivel y se sube | Programas conductores que llamen a los módulos ya listos (drivers) |
| Incremental combinada o sándwich | Se atacan a la vez los extremos y se juntan por el medio | Stubs y drivers, pero menos de cada uno |
| No incremental (big-bang) | Se prueba cada módulo por separado y después se conecta todo de una vez | Nada auxiliar, pero localizar un fallo se vuelve muy difícil |
La ventaja de la integración incremental es que, si algo falla al añadir un módulo, el culpable es casi siempre ese módulo. En big-bang todo aparece a la vez y el fallo puede estar en cualquier parte.
Para el examen
Integración incremental: si algo falla al añadir un módulo, el culpable es casi siempre ese módulo
Big-bang: todo aparece a la vez y el fallo puede estar en cualquier parte
Pruebas de regresión, alfa y beta
Las pruebas de regresión comprueban que un cambio no ha roto nada de lo que ya funcionaba. Consisten en volver a pasar las pruebas que antes pasaban, sobre partes que ni siquiera se han tocado, porque un cambio en un módulo puede alterar el comportamiento de otro que dependa de él.
No son un nivel más, sino una prueba que se hace en todos los niveles cada vez que hay una modificación: correctiva, evolutiva o incluso una refactorización que en teoría no cambia nada. Por eso son la primera candidata a automatizarse: hacerlas a mano después de cada cambio no es sostenible, y ese es justamente el motivo por el que existe la integración continua.
Regresión no significa probar lo nuevo, sino volver a probar lo viejo. Confundirla con las pruebas de la funcionalidad recién añadida es el fallo más repetido.
| Prueba | Dónde se hace | Con quién |
|---|---|---|
| Alfa | En un entorno controlado, en las instalaciones del desarrollador | Un usuario prueba y el desarrollador observa y toma nota |
| Beta | En el entorno de trabajo real del usuario | El usuario solo, sin observadores; los fallos los reporta él |
Para el examen
Regresión: volver a probar lo VIEJO, no lo nuevo
Para qué: comprobar que sigue funcionando
Alfa y beta: en casa del fabricante y con usuarios reales
Pruebas no funcionales
Las pruebas funcionales comprueban qué hace el sistema. Las no funcionales comprueban cómo lo hace: con qué rapidez, en qué condiciones, con qué seguridad y con qué comodidad para el usuario. Un sistema puede pasar todas las funcionales y ser inservible porque tarda treinta segundos en responder.
- Rendimiento: tiempos de respuesta y consumo de recursos con una carga determinada. De ahí salen las de carga, que llevan el sistema al volumen previsto, y las de estrés, que lo pasan a propósito para ver cómo se degrada.
- Seguridad: si el sistema resiste intentos de acceso indebido o de manipulación de datos.
- Usabilidad: si una persona real consigue hacer su tarea sin ayuda ni frustración.
- Compatibilidad: si funciona en los navegadores, sistemas operativos, dispositivos y versiones previstos.
- Otras habituales: disponibilidad, escalabilidad, portabilidad y mantenibilidad.
Hay además un corte transversal a todo lo anterior: las pruebas estáticas examinan el producto sin ejecutarlo, mediante revisiones, inspecciones de código y análisis automático de fuentes; las dinámicas requieren poner el programa a funcionar. Y una prueba muy usada en la práctica es la de humo, un conjunto rápido y superficial que se lanza sobre cada nueva versión para decidir si merece la pena probarla a fondo o si está tan rota que se devuelve.
Para el examen
Funcionales: comprueban QUÉ hace el sistema
No funcionales: comprueban CÓMO: rendimiento, carga, seguridad y usabilidad
Estáticas frente a dinámicas: no ejecutan el programa frente a sí ejecutarlo
Prueba de humo: decide si la versión merece probarse a fondo
Herramientas de prueba
Cada tipo de prueba tiene su familia de herramientas, y en examen se pregunta emparejando la herramienta con lo que prueba. Conviene fijarse en que las de análisis estático no ejecutan nada: leen el código fuente.
| Para qué | Herramientas habituales |
|---|---|
| Pruebas unitarias | JUnit en Java, NUnit en .NET y TestNG |
| Simular dependencias en pruebas unitarias | Mockito, que sustituye por objetos falsos lo que el componente necesita |
| Pruebas funcionales, simulando lo que hace el usuario | Selenium, SoapUI, Watir y WatiN |
| Pruebas de carga y rendimiento | JMeter, LoadRunner y LoadUI |
| Análisis de código estático | SonarQube, PMD, Checkstyle y FindBugs |
Un objeto simulado (mock) permite probar un componente sin arrastrar todo lo que hay debajo. Es lo que hace que una prueba unitaria sea de verdad unitaria y no una prueba de integración disfrazada.
Para el examen
Objeto simulado (mock): permite probar un componente sin arrastrar lo que hay debajo
Por qué importa: es lo que hace que una prueba unitaria sea de verdad unitaria