fbpx

Como ya hemos dicho, en el LNPS vemos la Prueba de Software como una disciplina en sí misma y por derecho propio.

Con un poco más de detalle, vemos el “problema de la Prueba de Software” de la siguiente manera:

Un producto de software puede verse como una Relación (en muchos casos una Función) que recibe Entradas y genera Salidas.

El Objetivo de la Prueba de Software es detectar en el Producto a Probar la mayor cantidad de Anomalías posible, lo más nocivas posible, lo antes posible, considerando el nivel de calidad requerido.

Y en esa búsqueda, vemos la cantidad de Anomalías en el producto como una función f de muchas variables, de las cuales las que hemos encontrado más determinantes son las siguientes:

Anomalías: f ( Complejidad, Duración, Cantidad, Proceso, Competencia, Herramientas )
donde

Complejidad es la complejidad del producto, que considera tanto la complejidad estructural como el tamaño;

Duración es la duración del proyecto para desarrollar el producto;

Cantidad es la  cantidad de personas involucradas en el desarrollo del producto;

Proceso es el proceso seguido para desarrollar el producto;

Competencia es la competencia de las personas involucradas en desarrollo del producto, que considera su conocimiento, experiencia, esmero, y perfil;

Herramientas son las herramientas utilizadas para desarrollar el producto.

Es natural que al tratar de alcanzar el Objetivo, se piense en desarrollar un primer programa que genere las Entradas (los “Casos de Prueba”) y las introduzca al Producto a Probar; y un segundo programa que calcule las salidas “correctas” (los “Resultados Esperados”) de manera independiente al Producto a Probar y las compare con las Salidas reales del Producto a Probar. Si una salida del segundo programa no es igual a la correspondiente Salida del Producto a Probar, entonces los programas habrían detectado una Anomalía.

Sin embargo, la prueba de software contiene varias limitantes inherentes al problema. Algunas de las más importantes son:

  • Desde el punto de vista teórico, la prueba es un problema que llamamos no-decidible. Esto significa, grosso modo, que en general no se puede escribir un programa que pruebe los programas sin intervención humana (sin embargo, la prueba sí es automatizable en muchas de sus fases particulares).
  • Desde el punto de vista práctico:
    • La cantidad de posibilidades para probar exhaustivamente un sistema es tan grande, que sencillamente se vuelve inmanejable (decimos que es un problema NP-Complete). Esto ha conducido al desarrollo de técnicas para maximizar la cantidad de Anomalías encontradas aplicando una pequeña cantidad de recursos (llamamos Heurísticas a estas técnicas, y se pueden entender intuitivamente como procesos que no buscan la mejor solución a un problema evaluando todas las alternativas sin importar el tiempo que eso requiera (como lo haría un Algoritmo), sino que buscan una buena solución evaluando solo las alternativas que parecen más prometedoras para entregar el resultado en un tiempo razonable).
    • Cada método que se utilice para detectar defectos deja un residuo de defectos más sutiles contra los cuales ese método es ineficaz (la llamada “Paradoja del Pesticida”).

Veamos esto a la luz de un caso concreto:

Supongamos que queremos probar un pequeño programa que recibe un valor entero y regresa el cuadrado del mismo. Pensemos que el programa tiene una interfaz con una caja de texto donde se captura el valor de entrada.

¿Cuántos casos de prueba serían necesarios para probar exhaustivamente ese pequeño programa?

Y, si tuviéramos a nuestra disposición 1,000 supercomputadoras capaces de realizar cada una 1021 operaciones por segundo (un millón de PetaFlops), y asumiéramos (sobre-simplificando las cosas) que aplicar un caso de prueba implicara solo una operación (se podrían aplicar 1024 casos de prueba por segundo): ¿en cuánto tiempo terminaríamos de probar exhaustivamente ese pequeño programa?

Tomemos la primera pregunta y supongamos que las supercomputadoras trabajan con un sistema de 64 bits. Podríamos pensar que debemos aplicar 264 casos de prueba (aproximadamente 1.84 x 1019), uno para cada número entero válido; sin embargo esto no sería exhaustivo ya que faltaría probar con números reales, con caracteres alfabéticos, con caracteres especiales, etc. Esto es: deberíamos probar toda cadena de caracteres que pudiéramos capturar en la caja de texto, tanto válidos como no válidos.

Pensemos que la caja de texto acepta un máximo de 20 caracteres (los 20 dígitos decimales que puede tener un entero de 64 bits), y obviemos las pruebas para verificar entradas con más de 20 caracteres; tendríamos que capturar todas las posibles combinaciones de 20 caracteres, que son 25620 (podemos representar 256 caracteres con un Byte); esto equivale aproximadamente a 1.46 x 1048 entradas de 20 caracteres. Utilizando las 1,000 supercomputadoras podríamos aplicar 1024 casos de prueba por segundo, así es que para aplicar todos los casos de prueba necesitaríamos 1.46 x 1024 segundos, que equivalen a 2.43 x 1022 minutos, a 4.05 x 1020 horas, a 1.69 x 1019 días, a 4.63 x 1016  años, o a 4.63 x 107 miles de millones de años (como referencia: la tierra tiene aproximadamente 4.5 x 103 miles de millones de años de existencia).

Estos números corresponden a la prueba exhaustiva de un pequeño programa que recibe sólo un valor. Si el programa recibiera 10 valores enteros (una cantidad de entradas más realista, pero aún lejana a la de un producto comercial), entonces necesitaríamos aplicar 4.40 x 10481 ( = (1.46 x 1048)10) casos de prueba, para lo cual requeriríamos 1.39 x 10441 miles de millones de años. Si tuviéramos no solo 1,000 super-computadoras a nuestra disposición, sino mil millones (109) de ellas, entonces el tiempo se reduciría a “solo ” 1.39 x 10435 miles de millones de años.

Los números son estratosféricos, aún para un programa pequeño. La conclusión es directa: desde el punto de vista práctico, probar exhaustivamente cualquier programa útil es una labor imposible; y desde el punto de vista “teórico-filosófico”, la idea de escribir un programa que compare las salidas con los resultados esperados, nos deja no sólo con el problema original de probar el producto, sino además con el problema de probar el programa que genera los resultados esperados.

La prueba es finalmente una práctica que utiliza métricas y aplica la estadística para detectar defectos; cuando no se realiza de esta manera se pierde efectividad y dinero.

Sin embargo, en el Laboratorio percibimos que la práctica común de la prueba de software en México (y en la mayor parte del mundo) se realiza en buena medida como hace 40 años:

  • Con procesos mal documentados, que en muchos casos no se siguen.
  • Con técnicas “propietarias” que no han demostrado ser efectivas, que no están documentadas y que no se aplican de manera homogénea.
  • Con muy pocas métricas para mejorar tanto la práctica de las pruebas, como la del desarrollo de software.

En el Laboratorio consideramos que es importante introducir mayor “formalidad” en las pruebas, aún –si no es que precisamente por ello– bajo las fuertes demandas actuales de que las pruebas deben realizarse más rápidamente, más frecuentemente y más tempranamente.

Con “mayor formalidad” nos referimos a la incorporación de implementaciones (intérpretes o compiladores, o componentes de ellos) de “Lenguajes Formales” (en el sentido que le da cualquier libro sobre “Autómatas y Lenguajes Formales”). Y pensamos así porque al hacerlo se abre una gran oportunidad para automatizar partes importantes de la práctica de la prueba de software, lo cual facilitaría el realizarla “más rápidamente, más frecuentemente y más tempranamente”.

Por ello vemos con buenos ojos el enfoque del “Formal Testing”, que –como elemento de definición– implica, en general, la introducción intensiva y extensa de implementaciones de lenguajes formales en tantas actividades de la prueba de software como sea posible. Dos de ellas se perciben imprescindibles:

  1. La introducción de implementaciones de lenguajes formales (intérpretes o compiladores, o componentes de ellos) para desarrollar modelos del Producto a Probar, a partir de los cuales pueda generarse automáticamente un volumen importante de productos relevantes de las pruebas (especialmente casos y scripts de prueba).
  2. La introducción de herramientas (“parsers”) para realizar Análisis Sintáctico del código fuente del Producto a Probar para por un lado detectar problemas iniciales provocados por malas prácticas de programación, diseño, etc.; y por otro para obtener información que abone al diseño de una buena Estrategia de Pruebas (como cuáles son los componentes del Producto a Probar más usados o más complejos, pues ellos debieran probarse proporcionalmente más que otros).

Un adicional e importante tipo de lenguajes formales que vemos que también debiera usarse en Formal Testing es el de los Process Definition Lenguages (ver sección “Proceso”).

El punto 1 podría cubrirse con herramientas existentes para hacer lo que llamaríamos “formal Model-Based Testing”, pero Formal Testing –como puede verse- va más allá.

                                                                 

Síguenos en :

Facebook
Facebook
YouTube
LinkedIn