Teoría sobre Deseño e realización de probas

De MediaWiki
Ir a la navegación Ir a la búsqueda
Mapa mental del tema

Sumario

Introducción

El testing

Las pruebas de software son las investigaciones empíricas y técnicas cuyo objetivo es proporcionar información objetiva e independiente sobre la calidad del producto a la parte interesada o stakeholder. Es una actividad más en el proceso de control de calidad.

Las pruebas son un conjunto de actividades dentro del desarrollo de software. Por lo tanto el modelos de pruebas será distinto dependiendo del modelo de desarrollo de software.

El objetivo de las pruebas no es asegurar la ausencia de defectos en un software, únicamente puede demostrar que existen defectos en el software. Nuestro objetivo es pues, diseñar pruebas que sistemáticamente saquen a la luz diferentes clases de errores, haciéndolo con la menor cantidad de tiempo y esfuerzo.

Características

Algunas características de una buena prueba son:

  • Ha de tener una alta probabilidad de encontrar un fallo. Para alcanzar este objetivo el responsable de la prueba debe entender el software e intentar desarrollar una imagen mental de cómo podría fallar.
  • Debe centrarse en dos objetivos. Probar si el software:
    • no hace lo que debe hacer
    • hace lo que no debe hacer.
  • No debe ser redundante. El tiempo y los recursos son limitados, así que todas las pruebas deberían tener un propósito diferente.
  • Debería ser la “mejor de la cosecha”. Esto es, se debería emplear la prueba que tenga la más alta probabilidad de descubrir una clase entera de errores
  • No debería ser ni demasiado sencilla ni demasiado compleja, pero si se quieren combinar varias pruebas a la vez se pueden enmascarar errores; por lo que en general, cada prueba debería realizarse separadamente.

Importancia

Su importancia es clave porque con este proceso se pretende:

  • que el software funciona acorde a los requisitos
  • que todos los requisitos hayan sido completados
  • validar que el elemento u objeto de nuestras pruebas es el esperado
  • incrementar la confianza en el desarrollo
  • encontrar fallos y defectos y prevenir su aparición
  • reportar al cliente el estado del software en términos de calidad y asegurar el cumplimiento de los acuerdos alcanzados

Todo ello redunda en una reducción de costes, plazos de entrega y riesgos a la par que aumenta la calidad aumentando la satisfacción del cliente.

Contexto clásico de la prueba de software y fases de la prueba

La figura muestra el contexto en el que se realiza la prueba de software. Concretamente la prueba de software se puede definir como una actividad en la cual:

  • un sistema o uno de sus componentes se ejecuta en circunstancias previamente especificadas (configuración de la prueba), registrándose los resultados obtenidos.
  • seguidamente se realiza un proceso de Evaluación en el que los resultados obtenidos se comparan con los resultados esperados para localizar fallos en el software.
  • estos fallos conducen a un proceso de Depuración en el que es necesario identificar la falta asociada con cada fallo y corregirla, pudiendo dar lugar a una nueva prueba.
  • como resultado final se puede obtener una determinada predicción de Fiabilidad o un cierto nivel de confianza en el software probado.
Contexto de la prueba de software

Veamos ahora cuáles son las tareas a realizar para probar un software:

  1. Diseño de las pruebas. Esto es, identificación de la técnica o técnicas de pruebas que se utilizarán para probar el software. Distintas técnicas de prueba ejercitan diferentes criterios como guía para realizar las pruebas. Seguidamente veremos algunas de estas técnicas.
  2. Generación de los casos de prueba. Los casos de prueba representan los datos que se utilizarán como entrada para ejecutar el software a probar. Más concretamente los casos de prueba determinan un conjunto de entradas, condiciones de ejecución y resultados esperados para un objetivo particular. Como veremos posteriormente, cada técnica de pruebas proporciona unos criterios distintos para generar estos casos o datos de prueba.
    Por lo tanto, durante la tarea de generación de casos de prueba, se han de confeccionar los distintos casos de prueba según la técnica o técnicas identificadas previamente. La generación de cada caso de prueba debe ir acompañada del resultado que ha de producir el software al ejecutar dicho caso.
  3. Definición de los procedimientos de la prueba. Esto es, especificación de cómo se va a llevar a cabo el proceso, quién lo va a realizar, cuándo, …
  4. Ejecución de la prueba. Aplicando los casos de prueba generados previamente e identificando los posibles fallos producidos al comparar los resultados esperados con los resultados obtenidos.
  5. Realización de un informe de la prueba. Con el resultado de la ejecución de las pruebas, qué casos de prueba pasaron satisfactoriamente, cuáles no, y qué fallos se detectaron.
  6. Proceso de depuración. Tras estas tareas es necesario realizar un proceso de depuración de las faltas asociadas a los fallos identificados.

Dentro del ciclo de vida del software en sus metologías más clásicas, las pruebas serían una fase a realizarse posteriormente al desarrollo:

Nuevos paradigmas: TDD y BDD

El desarrollo guiado por pruebas de software, o Test-driven development (TDD) es una práctica de ingeniería de software que involucra otras dos prácticas:

  • Escribir las pruebas primero (Test First Development)
  • la refactorización (Refactoring).

Los pasos serían:

  1. En primer lugar, se escribe una prueba y se verifica que la nueva prueba falla.
  2. A continuación, se implementa el código que hace que la prueba pase satisfactoriamente
  3. Seguidamente se refactoriza el código escrito.

El propósito del desarrollo guiado por pruebas es lograr un código limpio que funcione.

La idea es que los requisitos sean traducidos a pruebas; de este modo, cuando las pruebas pasen se garantizará que el software cumple con los requisitos que se han establecido.

Tener un único repositorio universal de pruebas facilita complementar TDD con otra práctica recomendada por los procesos ágiles de desarrollo: la integración continua. Integrar continuamente nuestro trabajo con el del resto del equipo de desarrollo permite ejecutar toda la batería de pruebas y así descubrir, si nuestra última versión es compatible con el resto del sistema.

Características de esta forma de programación:

  • evita escribir código innecesario (YAGNI "You Ain't Gonna Need It")
  • la generación de pruebas para cada funcionalidad hace que aumente la confianza del programador en el código escrito
Test-Driven Development

El desarrollo guiado por el comportamiento (DGC) o behavior-driven development (BDD) es una práctica en la ingeniería de software que surgió a partir del desarrollo guiado por pruebas.

El desarrollo guiado por el comportamiento combina las técnicas generales y los principios del DGP, junto con ideas del diseño guiado por el dominio y el análisis y diseño orientado a objetos para proveer al desarrollo de software y a los equipos de administración de herramientas compartidas y un proceso compartido de colaboración en el desarrollo de software.1

Behavior Driven Development

Error, defecto y fallo

Señalada la importancia de las pruebas, vamos a clarificar algunos de los conceptos asociados más importantes: el error, el defecto y el fallo.

Una persona puede cometer un error, que conlleva la introducción de un defecto en el código o en otras áreas del desarrollo del producto. Cuando un defecto introducido en el código es ejecutado en un test, se produce un fallo

Son muchas las causas que pueden provocar un error:

  • La presión del tiempo
  • Falta de conocimientos o de experiencia
  • Malentendidos en las comunicaciones del equipo
  • Complejidad de la solución
  • Errores en las Comunicaciones entre sistemas
  • Error humano
  • Nuevas tecnologías no suficientemente testadas

Niveles de testing

Test unitarios

Es la prueba que se realiza sobre la unidad más básica de nuestro código, métodos, funciones, clases, interfaces,...

Las pruebas unitarias son el método por el cual validamos que cada unidad desarrollada está lista para uso.

Los desarrolladores de software escriben estos casos de prueba para asegurar su funcionamiento en términos de diseño e implementación.

En ocasiones también los QAs pueden escribir estos casos de prueba, pero no es común.

Los test unitarios validan el correcto funcionamiento de la unidad más pequeña de código que utiliza nuestro software, por lo tanto lo que estamos consiguiendo es asegurar que para un conjunto de valores de entrada, nuestra función, método o clase devuelve el valor esperado.

Uno de los métodos utilizados es el de pruebas de caja blanca o TDD (Test Driven Development), entre otras, las cuales se detallaran más adelante.

Entre sus ventajas se encuentran:

  1. Los defectos aparecen temprano
  2. Ayuda a mantener el código
  3. Reduce el coste de solución
  4. Facilita las tareas de depuración

Hay que tener en cuenta que con su incremento pueden ralentizar los despliegues, y que su uso requiere concimiento: otra mentalidad al momento de escribir las pruebas, aprender el funcionamiento de la librería de pruebas, saber cómo trabajar con datos de prueba, saber abstraer/simplificar unas partes del sistema para poder escribir las pruebas, saber estructurarles, hacerlas resistentes al cambio y comprensibles, etc.

Test de integración

Un test de integración es aquel que combinando diferentes módulos prueba la comunicación entre ellos. Por ejemplo, comunicaciones:

  • Interfaz -> BBDD
  • Interfaz -> API
  • Interfaz -> Interfaz

Como estos sistemas ya tienen sus pruebas unitarias pasadas, los fallos detectados están realacionados con la interoperabilidad y la comunicación entre los mismos.

Normalmente cada equipo, o cada miembro de un equipo, desarrolla una parte del software. Por lo que, deben acordar, por ejemplo el paso de parámetros, o si tenemos que trabajar con una API de terceros, tendremos que seguir lo acordado en el juego de petición respuesta. Uno de los métodos utilizados es el de pruebas de caja negra, caja blanca o caja gris, entre otras, las cuales se detallaran más adelante.

Suelen ser también los desarrolladores los que escriben estos test en fases tempranas del desarrollo, cuando todavía no se implica al QA. Sin embargo, otra práctica habitual, es la de contratar a una empresa tercera especializada en pruebas.

Entre las estrategias de integración, podemos indicar las siguientes:

  1. Big bang
  2. Top down
  3. Bottom up
  4. Hibrido / sandwich

Test de sistemas

Las pruebas de sistema implican las pruebas del sistema al completo, desde que una acción es activada en el producto hasta que acaba.

De esta manera con todos los elementos integrados comprobaremos si el sistema al completo funciona como se espera o no.

Son los QAs especializados, o independientes, los que diseñan y ejecutan estos casos de prueba.

Los tipos de pruebas se pueden clasificar en funcionales y no funcionales.

Entre sus ventajas:

  • No es necesario tener ningún conocimiento de cómo se ha desarrollado el código.
  • Reduce los errores post-despliegue
  • Valoración de la experiencia de usuario
  • Multidisciplinar
  • Testing de navegación (Exploratory Testing)
  • Entornos para reproducir incidencias
  • Se prueban Arquitectura y Requisitos

Test de aceptación

Son las pruebas que se realizan sobre el producto final, si no en el entorno final, en uno practicamente igual.

Esta es la fase en la que el cliente decide el GO/NO GO del producto a un entorno productivo. Es el último paso para finalizar la entrega del producto al cliente.

Entre los objetivos de las pruebas de aceptación se encuentran:

  • Ganar confianza en el producto
  • Conseguir el OK para el paso a producción
  • Conseguir la aceptación del cliente de que lo que se ha diseñado y aprobado en las fases anteriores es realmente lo que el cliente pedía
  • Asegurar que el producto sigue los estándares de mercado (Lo prueban diferentes perfiles)
  • Comparar el producto con otros similares del mercado

Algunos de los tipos de test de aceptación son:

  • UAT (User Acceptance Testing)
  • BAT (Business Acceptance Testing)
  • CAT (Contract Acceptance Testing)
  • RAT (Regulations / Compliance Acceptance Testing)
  • OAT (Operational Acceptance Testing)
  • Alfa testing
  • Beta testing

Tipos de prueba

Funcionales

En ellas se comprueba lo que el sistema hace. La funcionalidad puede estar descrita en:

  • Requerimientos
  • Especificaciones funcionales
  • Casos de uso
  • No estar documentadas

Suelen estar relacionadas con las pruebas de caja negra.

Subclasificación según su ejecución: manuales y automáticas

A su vez, según su ejecución, las pruebas funcionales se clasifican en manuales y automáticas.

Las pruebas manuales son las que ejecuta un tester como si fuese un usuario pero siguiendo una serie de pasos establecidos o test plan, diseñado en el análisis de los requisitos para garantizar que hace lo que debe (casos positivos), que no falla (casos negativos) y que es lo que se ha solicitado.

El tester realizará las acciones indicadas en cada step del caso de prueba comprobando que se cumple el resultado esperado.

Si el resultado es distinto al esperado, se reportará un defecto con todo detalle: descripción, datos utilizados, capturas de pantalla, etc. para facilitar la solución del defecto por parte de los desarrolladores.

Las pruebas funcionales automáticas son pruebas funcionales que se automatizan para "ahorrar tiempo de pruebas". El objetivo de las pruebas funcionales automáticas es comprobar que nada de lo probado con anterioridad ha dejado de funcionar como debería.

A partir de los casos de prueba de las pruebas manuales, se automatizan los casos de prueba que se repitan en las ejecuciones. Esos casos suelen ser los más importantes (happy flow) de los módulos o procesos de negocio "vitales" de la aplicación, es decir, los procesos que siempre tienen que funcionar y que bajo ningún concepto pueden fallar.

Para esa automatización, estos deben ser los pasos a seguir:

  1. Elegir la prueba
  2. Precondición
  3. Pasos
  4. Comprobaciones
  5. Reporte estado final

No funcionales

Consideran el “comportamiento externo” del sistema comprobando cómo responde en términos de estrés, escalabilidad, carga, seguridad, etc.

Pueden hacer referencia a estándares de calidad, como el conjunto de normas ISO/IEC 25000|SQuaRE, ISO 25000:2014. Esta norma proporciona una guía para el uso de las series de estándares internacionales llamados requisitos y Evaluación de Calidad de Productos Software (SQuaRE). La norma establece criterios para la especificación de requisitos de calidad de productos software, sus métricas y su evaluación, e incluye un modelo de calidad para unificar las definiciones de calidad de los clientes con los atributos en el proceso de desarrollo.

Podemos clasificar las pruebas no funcionales según el tipo de requisito no funcional que abarcan:

  • Compatibilidad
  • Seguridad
  • Estrés
  • Usabilidad
  • Rendimiento
  • Internacionalización y localización
  • Escalabilidad
  • Mantenibilidad
  • Instalabilidad
  • Portabilidad

Regresivas

Son cualquier tipo de pruebas de software con el objeto de descubrir errores (bugs), carencias de funcionalidad, o divergencias funcionales con respecto al comportamiento esperado del software, causados por la realización de un cambio en el programa.

Se evalúa el correcto funcionamiento del software desarrollado frente a evoluciones o cambios funcionales. El propósito de éstas es asegurar que los casos de prueba que ya habían sido probados y fueron exitosos permanezcan así. Se recomienda que este tipo de pruebas sean automatizadas para reducir el tiempo y esfuerzo en su ejecución.

Técnicas de prueba

Caja blanca

Las técnicas de pruebas de caja blanca analizan las estructuras internas, las estructuras de datos utilizadas, el diseño interno, la estructura de código y el funcionamiento del software.

En este tipo de pruebas el código es accesible por el probador, por lo que tiene que tener conocimientos de codificación para entenderlo y diseñar las pruebas correspondientes.

Comprueban:

  • problemas de seguridad internos
  • mala o inexistente calidad en las estructuras de código
  • el flujo para cada input en el código
  • resultado esperado
  • funcionalidad de los bucles condicionales
  • prueba de cada declaración, objeto y función de forma individual

Se realizan de forma iterativa siguiendo estos tres pasos:

  1. Entender el código fuente
  2. Crear los casos de prueba
  3. Ejecutar los casos de prueba

Cobertura

Habitualmente es impracticable realizar una prueba exhaustiva de todos los caminos de un programa. Por ello se han definido distintos criterios de cobertura lógica, que permiten decidir qué sentencias o caminos se deben examinar con los casos de prueba. Estos criterios son:

  • Cobertura de Sentencias: Se escriben casos de prueba suficientes para que cada sentencia en el programa se ejecute, al menos, una vez.
  • Cobertura de Decisión: Se escriben casos de prueba suficientes para que cada decisión en el programa se ejecute una vez con resultado verdadero y otra con el falso.
  • Cobertura de Condiciones: Se escriben casos de prueba suficientes para que cada condición en una decisión tenga una vez resultado verdadero y otra falso.
  • Cobertura Decisión/Condición: Se escriben casos de prueba suficientes para que cada condición en una decisión tome todas las posibles salidas, al menos una vez, y cada decisión tome todas las posibles salidas, al menos una vez.
  • Cobertura de Condición Múltiple: Se escriben casos de prueba suficientes para que todas las combinaciones posibles de resultados de cada condición se invoquen al menos una vez.
  • Cobertura de Caminos: Se escriben casos de prueba suficientes para que se ejecuten todos los caminos de un programa. Entendiendo camino como una secuencia de sentencias encadenadas desde la entrada del programa hasta su salida.

De las técnicas expuestas, profundizaremos en tres conceptos asociados a las pruebas del camino básico

Cobertura de Caminos

La aplicación de este criterio de cobertura asegura que los casos de prueba diseñados permiten que todas las sentencias del programa sean ejecutadas al menos una vez y que las condiciones sean probadas tanto para su valor verdadero como falso. Una de las técnicas empleadas para aplicar este criterio de cobertura es la Prueba del Camino Básico. Esta técnica se basa en obtener una medida de la complejidad del diseño procedimental de un programa (o de la lógica del programa). Esta medida es la complejidad ciclomática de McCabe, y representa un límite superior para el número de casos de prueba que se deben realizar para asegurar que se ejecuta cada camino del programa.

Los pasos a realizar para aplicar esta técnica son:

  • Representar el programa en un grafo de flujo
  • Calcular la complejidad ciclomática
  • Determinar el conjunto básico de caminos independientes
  • Derivar los casos de prueba que fuerzan la ejecución de cada camino.
Representar el programa en un grafo de flujo

El grafo de flujo se utiliza para representar flujo de control lógico de un programa. Para ello se utilizan los tres elementos siguientes:

  • Nodos: representan cero, una o varias sentencias en secuencia. Cada nodo comprende como máximo una sentencia de decisión (bifurcación).
  • Aristas: líneas que unen dos nodos.
  • Regiones: áreas delimitadas por aristas y nodos. Cuando se contabilizan las regiones de un programa debe incluirse el área externa como una región más.
  • Nodos predicado: cuando en una condición aparecen uno o más operadores lógicos (AND, OR, XOR, ...) se crea un nodo distinto por cada una de las condiciones simples. Cada nodo generado de esta forma se denomina nodo predicado. La figura muestra un ejemplo de condición múltiple:
Representación de condición múltiple

Así, cada construcción lógica de un programa tiene una representación. La figura muestra dichas representaciones:

Representación en grafo de flujo de las estructuras lógicas de un programa
Cálculo de la complejidad ciclomática

La complejidad ciclomática es una métrica del software que proporciona una medida cuantitativa de la complejidad lógica de un programa. En el contexto del método de prueba del camino básico, el valor de la complejidad ciclomática define el número de caminos independientes de dicho programa, y por lo tanto, el número máximo de casos de prueba a realizar.

Dentro del contexto del método de pruebas del camino básico define el número de caminos independientes de un programa; se entiende como camino independiente aquel que introduce un nuevo conjunto de sentencias o una nueva condición. En términos del grafo, por una arista que no haya sido recorrida antes.

Formas de cálculo

Hay tres formas de realizar el cálculo de la complejidad ciclomática v(G):

1. El número de regiones del grafo es igual a la complejidad ciclomática.

V(G) = Nº de regiones

2. La complejidad ciclomática, V(G), de un grafo de flujo G se define como

V(G) = Aristas – Nodos + 2

3. La complejidad ciclomática, V(G), de un grafo de flujo G se define como

V(G) = Nodos Predicado + 1
Determinar el conjunto básico de caminos independientes

Un camino independiente es cualquier camino del programa que introduce, por lo menos, un nuevo conjunto de sentencias de proceso o una condición, respecto a los caminos existentes. En términos del diagrama de flujo, un camino independiente está constituido por lo menos por una arista que no haya sido recorrida anteriormente a la definición del camino. En la identificación de los distintos caminos de un programa para probar se debe tener en cuenta que cada nuevo camino debe tener el mínimo número de sentencias nuevas o condiciones nuevas respecto a los que ya existen. De esta manera se intenta que el proceso de depuración sea más sencillo.

El conjunto de caminos independientes de un grafo no es único. No obstante, a continuación, se muestran algunas heurísticas para identificar dichos caminos: (a) Elegir un camino principal que represente una función válida que no sea un tratamiento de error. Debe intentar elegirse el camino que atraviese el máximo número de decisiones en el grafo.

(b) Identificar el segundo camino mediante la localización de la primera decisión en el camino de la línea básica alternando su resultado mientras se mantiene el máximo número de decisiones originales del camino inicial.

(c) Identificar un tercer camino, colocando la primera decisión en su valor original a la vez que se altera la segunda decisión del camino básico, mientras se intenta mantener el resto de decisiones originales.

(d) Continuar el proceso hasta haber conseguido tratar todas las decisiones, intentando mantener como en su origen el resto de ellas.

Este método permite obtener V(G) caminos independientes cubriendo el criterio de cobertura de decisión y sentencia.

Derivar los casos de prueba que fuerzan la ejecución de cada camino

El último paso es construir los casos de prueba que fuerzan la ejecución de cada camino. Una forma de representar el conjunto de casos de prueba es como se muestra en la tabla:

Posible representación de casos de prueba para pruebas estructurales
Número del camino Caso de prueba Resultado esperado

Otras técnicas

Otras técnicas conocidas son:

Técnica Descripción
Prueba de interfaz Debe ser la primera a realizar. Se basa en analizar el flujo de datos que pasa a través de la interfaz del módulo, tanto externa como interna, para asegurar que la información fluye de forma adecuada tanto hacia el interior como hacia el exterior del módulo que se está probando.
Pruebas de estructuras de los datos locales Tienen como objetivo asegurar la integridad de los datos durante todos los pasos de la ejecución del módulo
Prueba del camino básico Permite obtener una medida de la complejidad lógica de un programa (complejidad ciclomática) y utilizar esa medida como guía para definir un conjunto básico de caminos de ejecución. Es decir, la prueba del camino básico se orienta a cubrir la ejecución de cada una de las sentencias, cada una de las decisiones y cada una de las condiciones en las decisiones, tanto en su vertiente verdadero como falsa.
Prueba de bucles Comprueban la validez de las construcciones de los bucles.
Prueba de bucles

Profundizaremos un poco más en esta técnica que se centra en la validez de las construcciones de los bucles, ya que son estos la piedra angular de la inmensa mayoría de los algoritmos implementados en software.

Se pueden definir cuatro tipos de bucles diferentes:

  • Bucles simples
  • Bucles concatenados
  • Bucles anidados
  • Bucles no estructurados.
Tipos de bucles

Bucles Simples:

A los bucles simples (de n iteraciones) se les tiene que aplicar el conjunto de pruebas siguientes:

  • Saltar el bucle
  • Pasar sólo una vez por el bucle
  • Pasar dos veces por el bucle
  • Hacer m pasos del bucle con m < n
  • Hacer n-1, n y n+1 pasos por el bucle

Bucles Anidados

Si extendiésemos el conjunto de pruebas de los bucles simples a los bucles anidados, el número de pruebas crecería geométricamente, por lo que Beizer sugiere el siguiente conjunto de pruebas para bucles anidados:

  • Comenzar con el bucle más interno, estableciendo los demás bucles a los valores mínimos
  • Llevar a cabo las pruebas de bucles simples para el bucle más interno, conservando los valores de iteración de los bucles más externos a los valores mínimos
  • Progresar hacia fuera en el siguiente bucle más externo, y manteniendo los bucles más externos a sus valores mínimos
  • Continuar hasta que se hayan probado todos los bucles

Bucles Concatenados

Existen dos situaciones

  • Si cada bucle es independiente del resto: Probar los bucles concatenados mediante las técnicas de prueba para bucles simples considerándolos como bucles independientes.
  • Si un bucle es dependiente de otro(por ejemplo contador del bucle 1 se usa como valor inicial del bucle 2) utilizar el mismo enfoque de bucles anidados

Bucles No Estructurados

Es necesario rediseñar estos bucles para que se ajusten a las construcciones de la programación estructurada.

Caja negra

Se define como una técnica de prueba en la que la funcionalidad de la aplicación bajo prueba, se prueba sin tener en cuenta la estructura del código interno, los detalles de implementación y el conocimiento de las estructuras internas del software. Este tipo de pruebas se basa completamente en los requisitos y especificaciones del software

Técnica Descripción
Dirigidas por la sintaxis Usada para examinar el formato y la gramática de los datos de entrada para realizar validaciones
Partición de equivalencia Consiste en dividir el dominio de entrada de un programa en clases de equivalencia de los que se pueden derivar casosde prueba, donde la prueba de un valor representativo de la misma sea extrapolable al que se conseguiría probando cualquier valor de la clase.
Análisis de valores límite Se elegirán como valores de entrada aquellos que se encuentra en el límite de las clases de equivalencia. Si una condición para un dato de entrada i especifica un rango de valores definido como n <= i <= m, los casos de prueba resultantes de aplicar el análisis de valores límite corresponden a n-1, n, n+1, m-1, m y m+1. Se justifica en la constatación de que para una condición de entrada que admite un rango de valores es más fácil que existan errores en los límites que en el centro. "Los errores se esconden en los rincones y se aglomeran en los límites” [Beizer].
Grafos causa efecto Permite al encargado de la prueba validar complejos conjuntos de acciones y condiciones.
Pruebas de Casos de uso Técnica de diseño de prueba de caja negra en la que los casos de prueba están diseñados para ejecutar escenarios de usuario.

Caja blanca vs caja negra

Caja blanca Caja negra
¿Qué valida? La estructura interna y el funcionamiento del código Los requisitos funcionales
Respecto al conocimiento del código.... El conocimiento del lenguaje de programación subyacente es esencial Proporcionan abstracción del código y se centran en el esfuerzo de probar el comportamiento del sistema de software
Sobre la comunicación... No facilitan la comunicación de pruebas entre los módulos Facilitan la comunicación de pruebas entre los módulos

Basadas en la experiencia - Alfa y beta testing

El Alpha Testing es un tipo de prueba de aceptación; se realiza para identificar todos los posibles problemas/errores antes de lanzar el producto a los usuarios o al público en general.

El objetivo de esta prueba es simular usuarios reales utilizando técnicas de Caja Negra y Caja Blanca. El objetivo es llevar a cabo las tareas que un usuario típico podría realizar.

El Beta Testing es la segunda fase del Software Testing en la que una muestra de la audiencia objetivo prueba el producto. Las pruebas beta de un software son realizadas por usuarios reales de la aplicación en un entorno real.

Tipo de Beta Testig Descripción
Tradicionales El producto se distribuye al mercado objetivo, y los datos relacionados se recopilan en todos los aspectos. Estos datos pueden ser utilizados para mejorar el producto.
Públicas El producto se da a conocer públicamente al mundo exterior a través de canales en línea y los datos se pueden obtener de cualquier persona
Ensayos Técnicos El producto se entrega al grupo interno de una organización y recoge los comentarios y datos de los empleados de la organización.
Enfocada El producto se lanza al mercado para recabar información sobre las características específicas del programa
Post-Lanzamiento El producto se lanza al mercado y se recopilan datos para hacer mejoras para el futuro lanzamiento del producto

Se puede ver una comparativa sobre las características del alfa y beta testing en la siguiente tabla:

Alfa Beta
Entorno Interno Del cliente
Equipos implicados Analistas de negocio y desarrolladores Solamente el cliente final está implicado en las pruebas y en el reporte
Conocimientos Equipo altamente cualificado en calidad Pueden ser usuarios finales ingenuos o competentes del producto
Caja Blanca y negra Negra
Cuando se realizan Antes del lanzamiento de un producto de software al mercado En el momento de la comercialización del producto de software
Objetivo Asegurar la calidad del producto Además recogen las opiniones de los usuarios sobre el producto y aseguran que este está listo para los usuarios en tiempo real
Fiabilidad y seguridad No se realizan pruebas de fiabilidad y seguridad Pruebas de fiabilidad, seguridad y robustez
Sobre el tiempo de ciclo Puede ser necesario un ciclo de ejecución largo Sólo se requieren unas pocas semanas de ejecución
Sobre cuándo se resuelven los problemas Los problemas críticos o correcciones pueden ser resueltos por los desarrolladores inmediatamente La mayoría de los problemas o comentarios que se recogen se implementarán en futuras versiones del producto

Organización de los casos de prueba y herramientas para su gestión

Es necesario organizar los casos de prueba para:

  1. Facilitar la comprensión del proyecto, desde un punto de vista de las pruebas.
  2. Comprender la funcionalidad y la prioridad fácilmente
  3. Facilitar las regresiones, completas o parciales
  4. Aumentar la calidad
  5. Facilitar la escalabilidad del proyecto

Algunos conceptos

Para esa organización, surgen algunos conceptos que deben ser clarificados:

  • Plan test:
  • Build:
  • Test suite:
  • Test case:

Conclusiones

Se ha presentado una visión global de las tareas de prueba y documentación ya que son de vital importancia durante el desarrollo de software.

Las pruebas buscan verificar que el software que se está creando es correcto y cumple con las especificaciones impuestas por el usuario, garantizando así la calidad del producto entregado.

Y por otra parte, una correcta documentación durante el desarrollo de software influirá también positivamente en la calidad del software, su utilización, soporte y posterior mantenimiento y evolución.

Anexo I - Herramientas Software para la realización de pruebas

Se presenta a continuación una tabla con varias herramientas que permiten la gestión y automatización de ciertos tipos de pruebas de software

Tipo de prueba Herramienta Lenguajes Comentario
Unitaria JUnit 5 Java
Mocha Javascript Test framework que corre en Node.js y en el navegador
PHPUnit PHP La versión 10 está en desarrollo
NUnit .NET
PyUnit Python
BDD Behat PHP Framework libre de Behavior-Driven Development para PHP
Cucumber Herramienta utilizada para ejecutar pruebas de aceptación automáticas creadas en formato BDD. Destaca su capacidad de llevar a cabo descripciones funcionales de texto sin formato (escritas en un lenguaje llamado Gherkin) como pruebas automatizadas.
Chai Javascript
Karma Javascript
Funcional y de regresión Selenium
Cypress Framework de pruebas todo en uno que facilita la integración continua
Integración SoapUI Aplicación de prueba de API para tecnologías SOAP y REST, permite también pruebas funcionales y de rendimiento
Postman Utilizada principalmente para el testing de API REST
Carga y rendimiento Apache JMeter
Gatling Herramienta para pruebas de estrés
LoadRunner
Aceptación FitNesse Herramienta de automatización de test de aceptación mediante su documentación en wiki
Concordion Framework orientado al desarrollo de tests de aceptación. Funciona a través de tests escritos en HTML
Acunetix Software de pruebas automáticas de seguridad web
Nessus Programa de escaneo de vulnerabilidades que permite agilizar pruebas de seguridad
Gestión TestLink
TestRail
Practitest
Múltiples Codeception PHP Permite realización de pruebas unitarias, integración, aceptación, BDD....
TestNG Java Framework para pruebas y testing que. Está basado en JUnit (para Java) y NUnit (para .NET) pero introduciendo nuevas funcionalidades que los hacen más poderosos y fáciles de usar.
Android Studio Kotlin (tambien Java y C++) Entorno de desarrollo integrado oficial para la plataforma Android, que también facilita el proceso de pruebas

Anexo II - Ejemplos de técnicas de prueba

Mediante tres pequeños ejemplos veremos algunas técnicas de prueba

Ejemplo 1: Días de la semana en formato numérico

  • La condición de entrada reflejaría que sólo se podrían introducir números del 1 al 7, ambos inclusive. Identificaríamos 2 clases:
    • Clase válida: 1 <= día <= 7
    • 2 clases no válidas: una cuando día < 1 y otra para día > 7

Ejemplo 2: Colores RGB en formato String minúscula

  • El valor de entrada sólo puede corresponder a uno de los colores RGB escrito en minúscula: «red», «green», «blue». Se supone que cada una de esas entradas se debería manejar de formas distintas en el programa.
    • 3 clases de equivalencia válidas, una para cada uno de los valores de entrada «red», «green» y «blue».
    • Una clase inválida que incluiría aquellos colores no especificados en la condición.

Ejemplo 3: Nombre con primera letra con mayúscula

  • Clase válida para cadenas cuya primera letra es una mayúscula (se cumple la condición)
  • Clase no válida para valores que no cumplen la condición: cadenas que comienzan en minúscula.

Partición de equivalencia

En forma de tabla, estas serían las particiones de equivalencia para los tres ejemplos anteriores:

Ejemplo de definición de particiones de equivalencia
Entrada Tipo Clases Válidas ID Clases no Válidas ID
Día de la semana Rango 1 <= día <= 7 v_dia día < 1 nv_dia_menor
día > 1 nv_dia_mayor
Colores Conjunto color = "red" v_color_r color distinto de los válidos nv_color
color = "green" v_color_g
color = "blue" v_color_b
Nombre de usuario Condición lógica Empieza por mayúscula v_mayúscula No empieza por mayúscula nv_mayúscula

Análisis de valores límite

En el ejemplo 1 anterior, deberíamos definir el rango de valores válidos como: 1 <= día <= 7. En ese caso, los casos de prueba resultantes a aplicar serían 0, 1, 2, 6, 7 y 8.

Valores límite en ejemplo de días de la semana

Caminos básicos y complejidad ciclomática

Cálculo de complejidad ciclomática

Bucles y cobertura

Anexo III - Ejemplos de estrategias de integración

Supongamos un ejemplo con los siguientes módulos:

Ejemplo de pruebas de integración

Estas serían las opciones para la realización de pruebas de integración.

Descendente, de arriba a abajo o top-down

  • El primer componente que se desarrolla y prueba es el primero de la jerarquía (A).
  • Los componentes de nivel más bajo se sustituyen por componentes auxiliares para simular a los componentes invocados.
  • En este caso no son necesarios componentes conductores.
  • Una de las ventajas de aplicar esta estrategia es que las interfaces entre los distintos componentes se prueban en una fase temprana y con frecuencia.

Ascendente, de abajo a arriba o bottom-up

  • En este caso se crean primero los componentes de más bajo nivel (E, F) y se crean componentes conductores para simular a los componentes que los llaman. * A continuación se desarrollan los componentes de más alto nivel (B, C, D) y se prueban.
  • Por último dichos componentes se combinan con el que los llama (A).
  • Los componentes auxiliares son necesarios en raras ocasiones.
  • Este tipo de enfoque permite un desarrollo más en paralelo que el enfoque de arriba abajo, pero presenta mayores dificultades a la hora de planificar y de gestionar.

Sandwich, híbridas o combinadas

  • A menudo es útil aplicar las estrategias anteriores conjuntamente.
  • De este modo, se desarrollan partes del sistema con un enfoque «top-down«, mientras que los componentes más críticos en el nivel más bajo se desarrollan siguiendo un enfoque «bottom-up«.
  • En este caso es necesaria una planificación cuidadosa y coordinada de modo que los componentes individuales se «encuentren» en el centro.

Big-Bang (gran explosión)

  • Esta última sería no incremental.
  • Se prueba cada componente por separado y posteriormente se integran todos de una vez realizando las pruebas pertinentes.

Anexo IV - Ejemplo de caso de prueba unitario con JUnit

Ejemplo de clase Calculadora con un método suma que devuelve como float la suma de dos parámetros de entrada float
public class Calculator {
   float add(float a, float b) {
       return a + b;
}
Caso de prueba para método add valida que 1 + 1 = 2
class MyFirstCalculatorTest {
  private final Calculator calculator = new Calculator();
   @Test
   void additionTest() {
       assertEquals(2, calcultaor.add(1,1), "La salida debe ser la suma de los dos argumentos: 1 +1 = 2");
   }
}

Anexo V - Herramientas Software para la documentación

Herramientas para la generación y publicación de documentación externa
Herramienta Comentario
Atlassian Confluence Módulo de Jira que permite documentar los how-to y las referencias técnicas llegando a asociar Ticket de Jira - Documentación de código – Rama de Git (o Subversion).
Read the Docs Plataforma gratuita para el alojamiento de documentación de software con código fuente; facilita la redacción de documentación técnica al automatizar la creación y el control de versiones.
Huddle Centro de colaboración todo-en-uno para los equipos. Utilizado por empresas grandes que necesitan herramientas estar sincronizadas, incluidos el almacenamiento de archivos, la gestión de proyectos y las herramientas de colaboración.
Sphinx Software generador de documentación que convierte ficheros reStructuredText en sitios web HTML y otros formatos, incluyendo PDF, EPub y man
Markdown Lenguaje de marcado ligero que trata de conseguir la máxima legibilidad y facilidad de publicación tanto en su forma de entrada como de salida
Y para la medición y análisis de la documentación:
Herramientas para la documentación de código y generación de APIs
Herramienta Comentario
Javadoc Permimte generar documentación de API en formato HTML desde el código fuente de Java.
phpDoc Es una adaptación de javadoc para php que define un estándar oficial para comentar código php.
Swagger Conjunto de herramientas de software de código abierto para diseñar, construir, documentar, y utilizar servicios web RESTful. Fue desarrollado por SmartBear Software e incluye documentación automatizada, generación de código, y generación de casos de prueba
.

Anexo VI - Ejemplo de documentación con JavaDoc

 /**
 * Una clase para representar círculos situados sobre el plano.
 * Cada círculo queda determinado por su radio junto con las 
 * coordenadas de su  centro.
 * @version 1.2, 03/02/21
 * @author José López Villar
 */

 public class Círculo {
    protected double x,y; // coordenadas del centro
    protected double r;  // radio del círculo
    
    /** 
     * Crea un círculo a partir de su origen su radio.
     * @param x La coordenada x del centro del círculo.
     * @param y La coordenada y del centro del círculo.
     * @param r El radio del círculo. Debe ser mayor o igual a 0.
     */
    public Circulo(double x, double y, double r) {
        this.x=x; this.y = y; this.r = r;
    }   
    
    /** 
     * Cálculo del área de este círculo.
     * @return El área (mayor o igual que 0) del círculo.
     */
     public double área() {
        return Math.PI*r*r;
     }


Anexo VII - Normas IEEE relacionadas con el software, su calidade, documentación y pruebas

Herramientas para la la medición y el análisis de la documentación
Herramienta Comentario
Google Analytics Permite el análisis de CTR, Tasa de rebote, tiempo en página, etc.
hotjar Permite comprender como los usuarios experimetan y evalúan la documentación analizando su comportamiento mediante encuestas y NPS
Estándar Nombre de la norma
IEEE 730 Planes de aseguramiento de la calidad del software.
ISO/IEC/IEEE 29119 Estándar de pruebas aplicable a todo tipos de sistemas y productos software. Cinco partes (Conceptos, procesos, documentación, Técnicas de prueba y Pruebas dirigidas por palabras clave). Reemplaza al estándar de documentación de pruebas de software IEEE 829
IEEE 982.1 Diccionario estándar de medidas para producir software fiable.
IEEE 982.2 Guía para el uso del diccionario estándar de medidas para producir software fiable.
IEEE 1008 Probas unitarias de software.
IEEE 1012 Verificación y validación de software.
IEEE 1028 Revisiones de software.
IEEE 1044 Clasificación estándar para anomalías do software.
IEEE 1061 Estándar para una metodología de métricas de calidad del software.
IEEE 1228 Planes de seguridad del software
ISO/IEC 25010 Modelo de calidad del producto compuesto por ocho características

Bibliografía

Referencias

Libros

JUnit