UP | HOME

Testing

Table of Contents

Ya se ha visto y se ha hecho hincapié que probar el software es obligatorio, importantísimo, una fase que no se puede saltar. Probar el software evitará plazos y presupuestos incumplidos, instatisfacción del usuario, pérdida de clientes, escasa productividad y mala calidad en el software producido.

Probar el software tiene por objeto asegurar la calidad, fiabilidad y funcionalidad del mismo identificando errores lo antes posible además de verificar que los requerimientos son conocidos. En muchos equipos y proyectos se tiene un equipo dedicado a dicha tarea porque los desarrolladores de un programa suelen probar lo que escriben con cierta benevolencia, por eso se suelen utilizar terceras personas para que prueben los programas sin contemplaciones.

En cualquier caso, nunca olvides que, como dijo el bueno de Edsger W. Dijkstra, "las pruebas solo pueden demostrar la presencia de errores, no su ausencia".

dijkstra.jpg

Figure 1: Fotografía obtenida en la Wikipedia

Alcance de las pruebas

Antes de dar comienzo a los diferentes tipos de pruebas, vamos a introducir un concepto importante y que te vas a encontrar constantemente: cobertura.

Llamamos alcance de las pruebas o cobertura al porcentaje de código que se prueba. Esto viene determinado por una fórmula matemática que da como resultado un tanto por ciento:

\begin{equation} cobertura = \frac{Número de sentencias ejecutadas}{Número de sentencias ejecutables \times 100} \end{equation}

Así pues, lo ideal es que dicha fracción nos de una valor igual al 100%, es decir, la prueba ideal sería probar todas las situaciones posibles. En la práctica es imposible a nivel humano, económico y matemático en muchos casos. Ten en cuenta que en un programa tenemos condicionales, bucles, ramas, métodos, recursividad, etc, que hace que tener una cobertura de pruebas completa sea imposible.

De todos modos, hay que intentar buscar una cobertura lo más grande posible y para ello hay una serie de técnicas que veremos más adelante.

Tipos de prueba

La siguiente imagen resume los tipos de prueba que vamos a estudiar y se explican a continuación:

esquema_clasificacion_pruebas.png

Figure 2: Imagen creada por Román Martínez con Inkscape

Básicamente las podemos englobar dentro de tres categorías:

  • En función del grado de automatización
  • En función del grado de conocimiento del código
  • En función del ciclo de vida en que se prueba

Estas tres categorías no son exclusivas, es decir, podemos tener una prueba que sea de caja negra (en función del grado de conocimiento), automática (en función del grado de automatización) y unitaria (en función del ciclo de vida en que se prueba).

Veamos, por categorías, brevemente, todos estos tipos de prueba.

Pruebas en función del grado de automatización

Las pruebas manuales son las pruebas que estarás harto de hacer cada vez que escribes un programa en el módulo de Programación, es decir, pruebas en las que te pones del lado del usuario final para comprobar que tu programa hace lo que esperas.

A su vez, las pruebas manuales pueden ser pruebas ad hoc, sin un plan establecido (seguramente lo que haces hoy en día) o pueden ser pruebas exploratorias si hay un plan diseñado.

En las pruebas automáticas se escriben piezas de software que prueban tu código. Estas pruebas son un programa paralelo o separado al que está desarrollando el programador que pueden estar escritas por el propio programador o por un equipo de testing diferente.

Las pruebas automáticas usan asserts en el código para validar que los resultados obtenidos son los esperados.

Pruebas en función del grado de conocimiento

Las pruebas de caja negra se llaman así porque no se conoce el código o no se tiene acceso a él. Así pues, lo único que podemos hacer es introducir una entrada y analizar la salida para comprobar si es lo que se espera.

Las pruebas de caja blanca se llaman así porque conocemos el código y, por tanto, podemos introducir una entrada para forzar que el programa viaje por un fragmento de código, entre a una función determinada, a un bloque de un if-else determinado, etc.

Pruebas en función del ciclo de vida en que se prueba

En esta categoría tenemos: pruebas unitarias, de integración, de sistema y de aceptación.

Las pruebas unitarias son aquellas en las que se prueban funciones, métodos o clases de forma aíslada. Son pruebas que se pueden realizar en fases muy tempranas del desarrollo.

Las pruebas de integración son pruebas que se realizan sobre varios componentes o módulos de la aplicación para evaluar cómo funcionan juntos. Un ejemplo típico es el de un programa que accede a una base de datos o a una API y queremos comprobar que dicha interacción se realiza con éxito y tal como se espera.

Las pruebas de sistemas se usan para comprobar qué tal se comporta el software bajo una condiciones técnicas concretas. Podemos dividir estas pruebas de sistema en dos:

  1. Pruebas de rendimiento en las que se miden aspectos como el tiempo de ejecución, la capacidad de respuesta y la escalabilidad del sistema. Se busca determinar cómo el software maneja la carga en situaciones normales y altas, asegurando que cumpla con los estándares de rendimiento establecidos.
  2. Pruebas de estrés en las que el software se somete a condiciones extremas, aumentando la carga de trabajo para evaluar su capacidad de resistir situaciones de alta presión. Estas pruebas verifican cómo el sistema consume recursos como memoria y CPU, permitiendo identificar puntos débiles y posibles puntos de fallo bajo presión.

Por último, las pruebas de aceptación son aquellas pruebas que realiza el usuario final con la idea de que pueda validar el software y aceptarlo (de ahí el nombre). Una vez aceptado se entrega el mismo. Dentro de las pruebas de aceptación si diferencian dos tipos:

  1. Pruebas alfa que se hacen junto al usuario final.
  2. Pruebas beta que las hace el usuario por su cuenta, probando el software y ofreciendo su feeling.

Casos de prueba (Test Case)

Un test case o caso de prueba es la descripción de una funcionalidad, característica o requisito a probar en un programa. Además de esta descripción, un caso de prueba, suele incluir, como mínimo, información como:

  • Condiciones de ejecución, es decir, el estado del sistema antes de ejecutar la prueba.
  • Entradas o los datos que se usan para la prueba.
  • Salida o resultados esperados, es decir, lo que se debe obtener si la parte que estamos probando funciona correctamente.

Si quieres una definición más formal, en la Wikipedia puedes encontrar que:

En ingeniería del software, un caso de prueba (en inglés: test case) es un conjunto de condiciones o variables bajo las cuales se determinará si una aplicación, un sistema de software o una característica o comportamiento de estos resulta o no aceptable.

Una funcionalidad puede ser probada por medio de varios casos de prueba. Hay metodologías como RUP (Rational Unified Process), por ejemplo, que recomienda un mínimo de dos casos de prueba para cada requisito: un caso de prueba realiza la prueba positiva y el otro caso de prueba realiza la prueba negativa.

Así, siguiendo con el ejemplo de RUP, si queremos probar una función que recibe una fecha y nos dice si es válida (verdadero) o no (falso), necesitamos dos prueba:

  • Prueba 1, caso positivo: pasar una fecha válida y comprobar que devuelve verdadero.
  • Prueba 2, caso negativo: pasar una fecha inválida y comprobar que devuele falso.

Ejemplo de caso de prueba

Imagina que tenemos que probar la funcionalidad de login de una programa. Podríamos tener, para probarlo, dos casos de uso como estos:

ID: Caso de prueba 1

Descripción:

  • Se quiere probar que la clase Login dejará entrar al usuario si dicho usuario y contraseña están en la base de datos registrado

Condiciones de ejecución:

  • En la base de datos se tiene un usuario "roman" con contraseña "123456".

Entrada:

  • usuario: "roman"
  • contraseña: "123456"

Salida:

  • Permite el acceso y muestra mensaje: "Has iniciado sesión correctamente"

ID: Caso de prueba 2

Descripción:

  • Se quiere probar que la clase Login impedirá entrar a un usuario no válido (no existente).

Condiciones de ejecución:

  • En la base de datos no se encuentra ningún usuario con nombre de usuario "gines" y contraseña "123456".

Entrada:

  • usuario: "gines"
  • contraseña: "123456"

Salida:

  • No deja entrar y muestra mensaje: "Usuario y/o contraseña no válido".

Plan de pruebas

Se trata de un documento que suele desarrollar un equipo de calidad (QA) junto al equipo de desarrollo, ingenieros de software, diseñadores y otros actores que participan en el proyecto.

En este documento se detalla el plan, es decir, los objetivos, tipos de prueba, plazos, etc, junto a los casos de prueba.

En este plan de pruebas se tiene que especificar cómo se van a ir recogiendo los resultados de las pruebas.

Grafo de posibles caminos en el enfoque caja blanca

grafo.png

Figure 3: Imagen obtenida en la Wikipedia

Cuando diseñamos pruebas y podemos usar el enfoque de caja blanca porque tenemos acceso al código podemos construir un grafo de posibles caminos que determinará los casos de prueba que tenemos que idear para conseguir una cobertura total.

La idea es la siguiente. Imagina que tienes el siguiente método:

metodo1.png

Figure 4: Método sobre el que construir el grafo de posibles caminos

Lo primero que tenemos que hacer es etiquetar de alguna forma las sentencias por las que se puede pasar cuando se ejecuta. Por ejemplo, por medio de números:

metodo2.png

Figure 5: Método con etiquetas para construir el grafo de posibles caminos

Y, ahora, solo hay que construir el grafo, partiendo de un nodo en blanco y terminando con otro nodo en blanco, que conecte todos los posibles caminos por los que se puede pasar:

grafo_final.png

Figure 6: Grafo de posibles caminos

Partiendo de este grafo, podemos elaborar un plan de pruebas con todas las posibilidades, como se representan en esta imagen:

casos_prueba.png

Figure 7: Plan de pruebas derivado del grafo de posibles caminos

Métodos para la realización de pruebas

Existen diversas técnicas de pruebas que ayudan a garantizar la calidad y el rendimiento de una aplicación. A continuación, te explico algunas de las técnicas más relevantes, incluyendo sus propósitos y enfoques:

  • Pruebas de Regresión (Regression Testing): se realiza para verificar que los cambios en el código (como nuevas características o correcciones de errores) no afecten negativamente a las funcionalidades existentes de la aplicación. Estas pruebas pueden ser manuales o automáticas, utilizando casos de prueba anteriores con lo que, así, verificamos que hemos "roto" nada que ya funcionaba.
  • Recorridos (Walkthroughs): esa una técnica donde se revisa un programa, normalmente en una fase temprana, y se analiza su diseño o código con la participación de varios programadores. De esta manera se retroalimentan los programadores y miembros del equipo al tiempo que se comprende mejor el software.
  • TDD (Test Driven Development): esa una técnica en la que se comienza por los tests automáticos y se van desarrollando las diferentes partes al conseguir que los tests automáticos resulten satisfactorios. Esto implica un ciclo iterativo de 5 pasos:
    1. Se escribe un test: este test prueba una nueva funcionalidad, por ejemplo.
    2. Se lanzan los tests: el test fallará porque no está la funcionalidad desarrollada.
    3. Se escribe el código necesario para pasar el test.
    4. Refactorizar: se optimiza el nuevo código asegurándose que el test sigue pasando.
  • BDD (Behaviour-Driven Development): es una extensión de TDD donde las pruebas se escriben usando un lenguaje natural a través de comentarios en el código o anotaciones. Es habitual el uso de "dado", "cuando", "entonces". Por ejemplo: "dado" un usuario y contraseña, "cuando" se introducen en el formulario, "entonces" se permite el acceso si es válido. Aquí se sigue un ciclo en el que se tienen estos pasos:
    1. Se define el comportamiento en formato historia o escenario.
    2. Escribir tests que describan el comportamiento.
    3. Escribir código, la funcionalidad, para pasar los tests.
    4. Refactorizar con la idea de optimizar y mejorar el código asegurándose que siguen pasando los tests.

Author: Román Ginés Martínez Ferrández

Created: 2026-05-05 mar 15:45

Validate