29 de enero de 2013

Mantenimiento del Software


El mantenimiento de software es una de las actividades más comunes en la Ingeniería de Software y es el proceso de mejora y optimización del software desplegado (es decir; revisión del programa), así como también corrección de los defectos. 

El mantenimiento de software es también una de las fases en el Ciclo de Vida de Desarrollo de Sistemas (SDLC ó System Development Life Cycle), que se aplica al desarrollo de software. 


FASE DE MANTENIMIENTO 

La fase de mantenimiento es la fase que viene después del despliegue (implementación) del software en el campo. 

La fase de mantenimiento de software involucra: 
  • Cambios al software en orden de corregir defectos.
  • Dependencias encontradas durante su uso tanto como la adición de nueva funcionalidad para mejorar la usabilidad y aplicabilidad del software. 

El mantenimiento de software involucra varias técnicas específicas. 

Una técnica es el rebanamiento estático, la cual es usada para identificar todo el código de programa que puede modificar alguna variable. 

Es generalmente útil en la refabricación del código del programa y fue específicamente útil en asegurar conformidad para el problema del año 2000 . 

La fase de mantenimiento de software es una parte explícita del modelo de cascada del proceso de desarrollo de software el cual fue desarrollado durante el movimiento de programación estructurada en computadoras. 

El otro gran modelo, el desarrollo en espiral desarrollado durante el movimiento de ingeniería de software orientada a objetos no hace una mención explícita de la fase de mantenimiento. 

Sin embargo, esta actividad es notable, considerando el hecho de que dos tercios del coste del tiempo de vida de un sistema de software involucran mantenimiento. 

En un ambiente formal de desarrollo de software, la organización o equipo de desarrollo tendrán algún mecanismo para documentar y rastrear defectos y deficiencias. 

El Software tan igual como la mayoría de otros productos, es típicamente lanzado con un conjunto conocido de defectos y deficiencias.

El software es lanzado con esos defectos conocidos porque la organización de desarrollo decide que la utilidad y el valor del software en un determinado nivel de calidad compensa el impacto de los defectos y deficiencias conocidas. 

Las deficiencias conocidas son normalmente documentadas en una carta de consideraciones operacionales o notas de lanzamiento (release notes) es así que los usuarios del software serán capaces trabajar evitando las deficiencias conocidas y conocerán cuando el uso del software sería inadecuado para tareas específicas. 

Con el lanzamiento del software (software release), otros, defectos y deficiencias no documentados serán descubiertas por los usuarios del software. 

Tan pronto como estos defectos sean reportados a la organización de desarrollo, serán ingresados en el sistema de rastreo de defectos. 

Las personas involucradas en la fase de mantenimiento de software esperan trabajar en estos defectos conocidos, ubicarlos y preparar un nuevo lanzamiento del software, conocido como una lanzamiento de mantenimiento, el cual resolverá los temas pendientes. 


TIPOS DE MANTENIMIENTO

A continuación se señalan los tipos de mantenimientos existentes, y entre paréntesis el porcentaje aproximado respecto al total de operaciones de mantenimiento: 

  • Perfectivo (60%): mejora del software (rendimiento, flexibilidad, reusabilidad) o implementación de nuevos requisitos. También se conoce como mantenimiento evolutivo. 
  • Adaptativo (18%): adaptación del software a cambios en su entorno tecnológico (nuevo hardware, otro sistema de gestión de bases de datos, otro sistema operativo...) 
  • Correctivo (17%): corrección de fallos detectados durante la explotación. 
  • Preventivo (5%): facilitar el mantenimiento futuro del sistema (verificar pre-condiciones, mejorar legibilidad...). 

Es importante tener en cuenta el efecto del Iceberg, es decir , en el momento en el que se le hace mantenimiento a un Software no se cuenta muchas veces con el factor económico (¿Cuánto dinero se invertirá en el mantenimiento ?), y una vez se comienza a desarrollar la fase de mantenimiento en la aplicación, comienzan a surgir nuevos requerimientos, el efecto del iceberg (en la superficie se ve solo una parte de lo que realmente es su tamaño).






24 de enero de 2013

Técnicas de Prueba

El desarrollo de Sistemas de software implica la realización de una serie de actividades predispuestas a incorporar errores (en la etapa de definición de requerimientos, de diseño, de desarrollo, ...).

Debido a que estos errores se deben a nuestra habilidad innata de provocar errores, tenemos que incorporar una actividad que garantice la calidad del software.


PROCESO DE PRUEBA



El proceso de prueba tiene dos entradas:

• Configuración del software: Incluye la especificación de requisitos del software, la especificación del diseño y el código fuente
• Configuración de prueba: Incluye un plan y un procedimiento de prueba

Si el funcionamiento del software parece ser correcto y los errores encontrados son fáciles de corregir, podemos concluir con que:

• La calidad y la fiabilidad del software son aceptables, o que
• Las pruebas son inadecuadas para descubrir errores serios


DISEÑO DE CASOS DE PRUEBA

Se trata de diseñar pruebas que tengan la mayor probabilidad de encontrar el mayor número de errores con la mínima cantidad de esfuerzo y de tiempo.

Cualquier producto de ingeniería se puede probar de dos formas:

Pruebas de caja negra: Realizar pruebas de forma que se compruebe que cada función es operativa.
Pruebas de caja blanca: Desarrollar pruebas de forma que se asegure que la operación interna se ajusta a las especificaciones, y que todos los componentes internos se han probado de forma adecuada.

En la prueba de la caja negra, los casos de prueba pretenden demostrar que las funciones del software son operativas, que la entrada se acepta de forma adecuada y que se produce una salida correcta.

En la prueba de caja blanca se realiza un examen minucioso de los detalles procedimentales, comprobando los caminos lógicos del programa, comprobando los bucles y condiciones, y examinado el estado del programa en varios puntos.

A primera vista, la prueba de caja blanca profunda nos llevaría a tener "programas 100 por cien correctos", es decir:
• Definir todos los caminos lógicos
• Desarrollar casos de prueba para todos los caminos lógicos
• Evaluar los resultados

Pero esto supone un estudio demasiado exhaustivo, que prolongaría excesivamente los planes de desarrollo del software, por lo que se hará un estudio de los caminos lógicos importantes.


PRUEBA DE LA CAJA BLANCA

La prueba de la caja blanca es un método de diseño de casos de prueba que usa la estructura de control del diseño procedimental para derivar los casos de prueba.


Las pruebas de caja blanca intentan garantizar que:
• Se ejecutan al menos una vez todos los caminos independientes de cada módulo
• Se utilizan las decisiones en su parte verdadera y en su parte falsa
• Se ejecuten todos los bucles en sus límites
• Se utilizan todas las estructuras de datos internas


Prueba del Camino Básico

El método del camino básico (propuesto por McCabe) permite obtener una medida de la complejidad de un diseño procedimental, y utilizar esta medida como guía para la definición de una serie de caminos básicos de ejecución, diseñando casos de prueba que garanticen que cada camino se ejecuta al menos una vez.

  • Notación del grafo de flujo o grafo del programa:

Representa el flujo de control lógico con la siguiente notación:



A continuación se muestra un ejemplo basado en un diagrama de flujo que representa la estructura de control del programa.




En el grafo de flujo
• Cada nodo representa una o más sentencias procedimentales
• Un solo nodo puede corresponder a una secuencia de pasos del proceso y a una decisión
• Las flechas (aristas) representan el flujo de control

Cualquier representación del diseño procedimental se puede traducir a un grafo de flujo.

Si en el diseño procedimental se utilizan condiciones compuestas, la generación del grafo de flujo tiene que descomponer las condiciones compuestas en condiciones sencillas, tal y como muestra la figura siguiente.




  • Complejidad Ciclomática:
Es una medida que proporciona una idea de la complejidad lógica de un programa.

• La complejidad ciclomática coincide con el número de regiones del grafo de flujo
• La complejidad ciclomática, V(G), de un grafo de flujo G, se define como:
                                                            V(G) = Aristas - Nodos + 2
• La complejidad ciclomática, V(G), de un grafo de flujo G, también se define como:
                                                          V(G) = Nodos de predicado + 1

A partir del grafo de flujo, la complejidad ciclomática sería:
• Como el grafo tiene cuatro regiones, V(G) = 4
• Como el grafo tiene 11 aristas y 9 nodos, V(G) = 11 - 9 - 2 = 4
• Como el grafo tiene 3 nodos predicado, V(G) = 3 + 1 = 4

A partir del valor de la complejidad ciclomática obtenemos el número de caminos independientes, que nos dan un valor límite para el número de pruebas que tenemos que diseñar.

En el ejemplo, el número de caminos independientes es 4, y los caminos independientes son:
• 1-11
• 1-2-3-4-5-10-1-11
• 1-2-3-6-7-9-10-1-11
• 1-2-3-6-8-9-10-1-11

  • Pasos del diseño de pruebas mediante el camino básico:
• Obtener el grafo de flujo, a partir del diseño o del código del módulo

• Obtener la complejidad ciclomática del grafo de flujo

• Definir el conjunto básico de caminos independientes

• Determinar los casos de prueba que permitan la ejecución de cada uno de los caminos anteriores

• Ejecutar cada caso de prueba y comprobar que los resultados son los esperados


Prueba de Bucles

Los bucles son la piedra angular de la inmensa mayoría de los algoritmos implementados en software, por lo que tenemos que prestarles una atención especial a la hora de realizar la prueba del software.

La prueba de bucles es una técnica de prueba de caja blanca que se centra en la validez de las construcciones de los bucles.

Se pueden definir cuatro tipos de bucles diferentes:
• Bucles simples
• Bucles concatenados
• Bucles anidados
• Bucles no estructurados



  • 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:
Probar los bucles concatenados mediante las técnicas de prueba para bucles simples, considerándolos como bucles independientes.


  • Bucles No Estructurados:
Rediseñar estos bucles para que se ajusten a las construcciones de la programación estructurada.

Ejemplo:
Construir el Grafo de Flujo correspondiente a la siguiente especificación del software en LDP.

Solución:


Ejemplo: 
Construir el Grafo de Flujo correspondiente al siguiente código de un programa


Solución:


PRUEBA DE LA CAJA NEGRA

Las pruebas de caja negra se llevan a cabo sobre la interfaz del software, obviando el comportamiento interno y la estructura del programa.

Los casos de prueba de la caja negra pretenden demostrar que:
• Las funciones del software son operativas
• La entrada se acepta de forma correcta
• Se produce una salida correcta
• La integridad de la información externa se mantiene

A continuación se derivan conjuntos de condiciones de entrada que utilicen todos los requisitos funcionales de un programa.

Las pruebas de caja negra pretenden encontrar estos tipos de errores:
• Funciones incorrectas o ausentes
• Errores en la interfaz
• Errores en estructuras de datos o en accesos a bases de datos externas
• Errores de rendimiento
• Errores de inicialización y de terminación

Los tipos de prueba de cana negra que vamos a estudiar son:
• Prueba de partición equivalente
• Prueba de análisis de valores límites


Prueba de Partición Equivalente

Este método de prueba de caja negra divide el dominio de entrada de un programa en clases de datos, a partir de las cuales deriva los casos de prueba.
Cada una de estas clases de equivalencia representa a un conjunto de estados válidos o inválidos para las condiciones de entrada.

  • Identificación de las clases de equivalencia:
Se identifican clases de equivalencia válidas e inválidas con la siguiente tabla: 


A continuación se siguen estas directrices:
• Si una condición de entrada especifica un rango de valores (p.e, entre 1 y 999), se define una CEV (1 <= valor <= 999) y dos CEI (valor < 1 y valor > 999)
• Si una CE requiere un valor específico (p.e., el primer carácter tiene que ser una letra), se define una CEV (una letra) y una CEI (no es una letra)
• Si una CE especifica un conjunto de valores de entrada, se define una CEV para cada uno de los valores válidos, y una CEI (p.e., CEV para "Moto", "Coche" y "Camión", y CEI para "Bicicleta")
• Si una condición de entrada especifica el número de valores (p.e., una casa puede tener uno o dos propietarios), identificar una CEV y dos CEI (0 propietarios y 3 propietarios)

  • Identificación de casos de prueba:
Seguir estos pasos
• Asignar un número único a cada clase de equivalencia
• Escribir casos de prueba hasta que sean cubiertas todas las CEV, intentando cubrir en cada casos tantas CEV como sea posible
• Para cada CEI, escribir un caso de prueba, cubriendo en cada caso una CEI

Ejemplo
Diseñar casos de prueba de partición equivalente para un software que capte estos datos de entrada:

• Código de área: En blanco o un número de tres dígitos
• Prefijo: Número de tres dígitos que no comiencen por 0 ó 1
• Sufijo: Número de cuatro dígitos
• Ordenes: "Cheque", "Depósito", "Pago factura"
• Palabra clave: Valor alfanumérico de 6 dígitos