Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Fundamentos de las pruebas de software en Javascript

Contenidos
  1. Aseguramiento de calidad en Software
  2. Pruebas Unitarias
  3. Pirámide del testing
  4. Errores vs Fallas
  5. Pruebas manuales
  6. Implementación en corroboración de algoritmos.
  7. TDD y BDD

Aseguramiento de calidad en Software

En este capítulo nos centraremos en la verificación del software mediante pruebas automatizadas, parte fundamental del ciclo de vida de los activos digitales.

Aún cuando la verificación mediante pruebas automatizadas es una de las formas más eficientes para mejorar la calidad del software en cuanto a legibilidad y mantenibilidad, muchas empresas y desarrolladores malinterpretan su rol y no es priorizado como otras partes del ciclo (pero casi todos tienen tableros muy way).

Código testeable tiende a ser código limpio y viceversa

En los equipos ágiles, se espera que los desarrolladores escriban pruebas al código que desarrollan, mientras que los equipos de QA se encargan de que los errores reportados por los usuarios puedan ser reproducibles para encontrar una solución apropiada (si el error no se puede replicar es muy difícil saber si un cambio lo corrige sin introducir errores o bugs) y que ciertos elementos visuales sean particularmente atractivos o visibles según los lineamientos de diseño de experiencia UX/UI.

En general se requiere probar automatizadamente todo código no trivial para asegurar que:

El código existente se comporta según las especificaciones

Cualquier código nuevo no rompe el comportamiento definido por las especificaciones

Pruebas Unitarias

La unidad a testear es una unidad lógica que constituye un solo comportamiento. Esta unidad debe poder ser invocada mediante una interfaz pública y debe ser testeada de forma independiente. Para lograr la independencia de la unidad de código a testear necesitaremos proveer de todas las precondiciones que requiere mediante dobles de prueba. Veremos en detalle como crear estos dobles de prueba para reemplazar dependencias en pruebas unitarias en los laboratorios.

Pirámide del testing

Metáfora que nos muestra la agrupación por cantidad y costo de los principales tipos de prueba.

Links a imágenes

Errores vs Fallas

Un error en una prueba unitaria en JavaScript se refiere a un problema en el código de la prueba en sí mismo, como un sintaxis incorrecta o una referencia a una variable no definida. Por otro lado, un fallo en una prueba unitaria se refiere a cuando el código bajo prueba no se comporta de la manera esperada, lo cual puede ser causado por un error en el código del sistema bajo prueba. En resumen, un error es un problema en el código de la prueba, mientras que un fallo es un problema en el código bajo prueba.

Pruebas manuales

En estos ejercicios probaremos una librería externa y lo haremos de forma incremental. Desde pruebas manuales, luego un poco de automatización para finalmente crear un mini framework declarativo con una mínima librería de corroboraciones (matchers) y un simple test runner.

Importamos el código y generamos varias pruebas manuales para revisar de forma manual o visual si funciona o no el algoritmo

  const NumberToWord = require('../SUT/utils/numberToWord')

  const numberToWord = new NumberToWord()
  
  console.log(numberToWord.convert(21000))
  console.log(numberToWord.convert(31121051))
  console.log(numberToWord.convert(5000))
  console.log(numberToWord.convert(999))
  console.log(numberToWord.convert(25990))

Implementación en corroboración de algoritmos.

Prueba realizada utilizando programación.

Estamos utilizando programación para corroborar a través de un simple algoritmo una serie de pruebas.


const NumberToWord = require('../SUT/utils/numberToWords')
const tests = [
  { value: 5000, expected: 'cinco mil' },
  { value: 999, expected: 'novecientos noventa y nueve' },
  { value: 25990, expected: 'veinticinco mil novecientos noventa' },
  { value: 21000, expected: 'veintiún mil' },
  { value: 31121051, expected: 'treinta y un millones ciento veintiún mil cincuenta y uno' },
]

const numberToWord = new NumberToWord()

tests.forEach(({ value, expected }) => {
  const newValue = numberToWord.convert(value)
  if (newValue !== expected) {
    const errorMessage = `❌ La prueba para el valor "${newValue}" falló. El valor esperado era "${expected}"`
    console.log(errorMessage)
    throw new Error(errorMessage)
  }
})

TDD y BDD

El desarrollo guiado por pruebas (TDD) se ha vuelto muy popular en la última década, pero el concepto se originó en la metodología llamada programación extrema de Kent Beck. La idea es tener ciclos cortos de desarrollo con el foco puesto en escribir inicialmente los casos de prueba. Podemos describir sus pasos de la siguiente forma:

  1. Agregar los casos de prueba según las especificaciones para una unidad de código específica.
  2. Correr los casos de prueba y corroborar que estén fallando. Esto asegura que la capa de tests funciona según lo esperado.
  3. Escribir el código mínimo que sirve para pasar las pruebas. Este código no está optimizado ni contiene las mejores prácticas o está completamente correcto, pero para esta etapa es suficiente.
  4. Volver a correr las pruebas y confirmar que todas las pruebas pasan. Luego de este paso estamos seguros que el nuevo código no rompe otros casos de prueba ni interfiere con otras funcionalidades.
  5. Refactorizar el código para optimizar su mantenibilidad y que los casos de borde están apropiadamente considerados.

Estos pasos son repetidos por cada código agregado. Esta estrategia funciona bien en entornos ágiles. TDD es una metodología segura si las unidades de código son pequeñas y están desarrolladas para soportar casos de prueba.

Un problema de TDD es su vocabulario y definición de qué es correcto. BDD introduce un lenguaje común ara escribir casos de prueba para seguir TDD. Este lenguaje permite que los desarrolladores y personas de negocio hablen lo mismo.