Conceptos básicos Pruebas de Software

Las Pruebas de software es el proceso de ejecutar programas o aplicaciones con el propósito de encontrar errores en ellos. Con las pruebas se puede mostrar la presencia de un error pero no la ausencia (Dijkstra).

Los errores de un programa o aplicación pueden ser de distintos tipos. Pueden ser funcionales, es decir el programa no se comporta funcionalmente como se espera. Pueden ser errores asociados con atributos de calidad de la aplicación. Por ejemplo, se espera que la aplicación pueda atender simultáneamente, con un desempeño dado, un millón de usuarios (atributo de escalabilidad) pero su desempeño se deteriora y no puede cumplir ese requerimiento.

En este curso vamos a estudiar pruebas de funcionalidad. Los otros tipos de pruebas se ven en el curso de Arquitectura de Software. En cualquier caso, ya sea que se trate de pruebas de funcionalidad u otras, siempre vamos a querer automatizar las pruebas. Es decir, programarlas y utilizar herramientas para que se puedan ejecutar de manera repetible y _automática _cada vez que se cambia el software.

Para hacer esto de manera más fácil existen los frameworks de pruebas, para la gran mayoría de los lenguajes de programación. La arquitectura de frameworks de prueba más conocida es xUnit. En el caso de java, se llama Junit y fue desarrollado por dos Ingenieros de Software Kent Beck y Erich Gamma en el año 2004. Al final de este tema se pueden encontrar referencias y material complementario sobre las pruebas, los frameworks y los ingenieros de software que los desarrollaron.

Vamos a ver primero un vocabulario básico sobre las pruebas de software, luego discutiremos las estrategias para desarrollar software y sus pruebas de manera simultanea utilizando Junit. Adicionalmente, veremos como crear pruebas automatizadas para aplicaciones JEE, como automatizarlas para que sean ejecutadas por la herramienta de integración continua (jenkis, hudson, travis, etc.) y que además los resultados de las pruebas y las métricas de cubrimiento puedan desplegarse en el tablero de control de calidad de la aplicación (SonarQube en nuestro caso).

Técnicas de Pruebas

De acuerdo con el conocimiento que debe tener sobre el código el desarrollador de las pruebas, las técnicas de desarrollo se llaman caja blanca, caja gris y caja negra, así:

  • Caja blanca o pruebas estructurales: El conocimiento del diseño interno del software se usa para desarrollar los casos de pruebas
  • Caja gris: No es necesario el conocimiento detallado del software pero si de las signaturas de los métodos que implementa.
  • Caja negra o pruebas funcionales: Los casos de prueba son diseñados basados sólo en la especificación externa del software. También se llaman Pruebas basadas en escenarios o casos de uso.

Tipos de Pruebas

De acuerdo con el propósito de la prueba, quién la realiza y en qué ambiente se hace, las pruebas se pueden clasificar en los siguientes tipos:

Tipo de Prueba Propósito Quién la desarrolla Técnica de Prueba
Unitarias Encontrar errores en la lógica, datos o algorítmos de los métodos de los componentes El mismo desarrollador del método Caja blanca y Caja gris
Integración Encontrar errores en las interfaces entre los módulos Realizado por los desarrolladores de los módulos que serán integrados Caja gris basado en las especificaciones de las interfaces
Sistema Encontrar errores en el comportamiento del sistema de acuerdo con la especificación de requerimientos Realizado por un grupo diferente al de desarrollo Caja negra basado en los requerimientos y en escenarios reales
Aceptación Son las mismas pruebas de sistema pero realizadas en el ambiente del cliente Usuarios que representan al cliente Caja negra basado en los requerimientos y en escenarios reales

Todos los tipos de prueba se pueden automatizar incluyendo las de sistema y aceptación. En cada caso existen herramientas para apoyar esa labor.

Pruebas de Regresión

Muchas veces ocurre que al modificar alguna parte del software ya sea para agregar algo nuevo o para cambiar algo existente, introducimos una regresión, es decir, dañamos algo que ya estaba funcionando. Lo más complejo de esto es que muchas veces ni siquiera nos damos cuenta de cuándo ocurrió.

Es por está razón que es muy importante tener las pruebas automatizadas para que se puedan repetir cada vez que se hace un cambio. Cuando volvemos a ejecutar las pruebas para verificar que no introdujimos un error o una regresión en la aplicación, a este proceso lo llamamos Pruebas de Regresión.

Prueba y Caso de prueba

No hay un acuerdo general sobre la diferencia entre prueba (test) y caso de prueba (test case). En el contexto de este libro hablaremos de la prueba como la estrategia general para probar algo y el caso de prueba es el conjunto de datos que se utilizarán para ejecutar la prueba. Significa que una misma prueba puede tener muchos casos de prueba. Por ejemplo, si tenemos un método de calcular unos intereses de acuerdo con un parámetro de entrada:

public Double interest(int interestType, Double value) 
 {

        if (interestType == 0) {
            return value * 0.15;
        } else {
            return value * 0.85;
        }
    }

Una prueba para este método, llamemosla interestTest, puede ser definida para que invoque el método con un _interestType _y un _value _y compare el resultado esperado con el producido.

Esta prueba tendrá tantos casos de prueba como valores distintos definamos para los argumentos del método. Por ejemplo:

Caso de prueba interestType value Respuesta esperada
1 0 10 1,15
2 0 -10 -1,15
3 0 10 8,5

En este ejemplo hay 3 casos de prueba para la prueba interestTest.

Cubrimiento de las pruebas

El cubrimiento o cobertura de las pruebas (test coverage) es una métrica que indica el porcentaje de código que se ejecutó dado un conjunto de pruebas y de casos de prueba. Si en el ejemplo anterior para el código del método interest tenemos la prueba interestTest pero únicamente los casos de pruebas 1 y 2, solo se ejecutará el 50% del código. Diremos que el cubrimiento de las pruebas es del 50%. Si tenemos los 3 casos de prueba, el cubrimiento será del 100%.

Siempre tendremos interés en mantener el valor de cubrimiento de las pruebas muy alto, sin embargo, cuando hay cientos o miles de líneas de código en un programa es muy difícil tener pruebas y casos de prueba para un cubrimiento del 100%.

Referencias y material complementario

The-history-of-junit

Kent Beck Erich Gamma

http://junit.org/junit4/

results matching ""

    No results matching ""