Introducción al Testing

DEFINICIÓN

Software testing es el proceso de ejecutar un programa o aplicación con el objetivo de encontrar sus errores (bugs).

Es también el proceso de validar y verificar que un software:

  • Cumple con los requisitos técnicos y de negocio con los que se diseñó.
  • Se integra y ejecuta tal y como se esperaba.
  • Puede ser implementado, ejecutado y escalado con las misma características a lo largo de su vida. (sin deuda técnica)

DEFINICIÓN

Prueba manual.

Un Test manual es usar el software como si fuésemos el usuario final. Suele implementarse mediante un check-list extraído de los requisitos/casos de uso.

Prueba automatizada.

Un Test automatizado es código que verifica el correcto funcionamiento de otro código.

Las pruebas de software son una serie de procesos que investigan y evalúan la calidad del software. Asegura que el producto de software se construya según los requisitos

Beneficios

De cara al cliente:

Requisitos: Nos permiten verificar que cumplimos con los requisitos exigidos.

Satisfacción del cliente: Encontrar errores antes de que lleguen al usuario final.

Usabilidad: Encontrar problemas de usabilidad.

En desarrollo:

Depuración: Los errores que aparecen en producción son más difíciles de depurar, porque tenemos menos contexto.

Coste

¡¡TIEMPO!!

Tiempo para crear pruebas, tiempo de ejecutarlas, tiempo del departamento de QA...

Beneficios. Automatizar

Rapidez: Las pruebas automatizadas son más rápidas que las manuales.

Fiabilidad: Las pruebas realizan exactamente las mismas operaciones cada vez que se ejecutan, eliminando el error humano.

Repetición/Estrés: El coste de cada repetición es casi nulo. Podemos realizar pruebas en paralelo para verificar distintos comportamientos.

Programable: Se pueden realizar pruebas mucho más sofisticadas de forma más sencilla.

Reusabilidad: Podemos reutilizar los scripts de unas pruebas para hacer nuevas pruebas.

Desafios.

Curva de aprendizaje bastante elevada.

Aumento del tiempo de codificación. (pruebas + código) (+ al principio).

Aparecen nuevos tipos de errores. “¿Pruebas de las pruebas?”.

Saber que NO PROBAR porque no aporta confianza. (coste/beneficio)

No probar detalles de implementación. (Pruebas débiles)

Hacer código fácil de probar

TDD. Test-Driven Development

Desarrollo guiado por pruebas de software, o Test-Driven Development (TDD) es una práctica de ingeniería de software compuesta por dos prácticas: Escribir las pruebas primero (Test First Development) y Refactorización (Refactoring).

Las 3 Leyes del TDD @ Uncle Bob.

  • You are not allowed to write any production code unless it is to make a failing unit test pass.
  • You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  • You are not allowed to write any more production code than is sufficient to pass the one failing unit test

TDD. Test-driven development

  • No se permite escribir ningún código de producción, a menos que sea para hacer pasar un test unitario fallido.
  • No se permite escribir más que un test unitario que sea lo mínimo imprescindible para que éste falle; los errores de compilación se consideran fallos.
  • No se permite escribir ningún código de producción más allá del necesario para hacer pasar un test unitario.

TDD. Beneficios

Evitamos escribir código innecesario.

Obtenemos código documentado por código.

Reduce el tiempo de depuración y resolución de fallos.

Podemos refactorizar sin miedo.

Mejora del API. Consumimos a la vez que producimos.

Flujo continuo de Tareas + Análisis + Correcciones == Gestión Ágil.

Aumenta la velocidad del equipo. (bug-fixing del sprint anterior)

TDD. Beneficios

CONFIANZA.

Si TODO tu código ha sido construido cumpliendo las 3 leyes, TODO tu código funciona.

@Uncle Bob

TDD. Desafios

Curva de aprendizaje bastante elevada.

Aumento del tiempo de codificación. (pruebas + código) (+ al principio).

Aparecen nuevos tipos de errores. “¿Pruebas de las pruebas?”.

Saber que NO PROBAR porque no aporta confianza. (coste/beneficio)

No probar detalles de implementación. (Pruebas débiles)

Hacer código fácil de probar / ¿Pensar las pruebas a la vez que el código?.

Herramientas

Suite de Test:

  • Ejecutar los test: Test Runner
  • Escribir los test: Módulo de test
  • Escribir validaciones: Módulo de asserts.
  • Suplantar partes del sistema: Módulo de mocks.

La mayoría de los frameworks vienen con una suite por defecto.

Tipos de Pruebas

Estáticas: Detectan errores de escritura y promueven buenas prácticas.

Unitarias: (TDD) Verifican el correcto funcionamiento de una unidad de código.

Integración: (TDD) Verifican el correcto funcionamiento de las distintas unidades de código entre sí.

Extremo a Extremo (E2E): Prueban el sistema de principio a fin, incluyendo todos los sistemas involucrados en el software.

UI: Unitarias/Integración/E2E centradas en la interfaz gráfica.

Code Review: Revisión del código entre miembros del equipo

Estáticos o de tipado.

  • PyLint
  • EsLint
  • PHPLint

Estructura de un Test

Siguen la estructura AAA

  • Arrange: Preparamos los elementos necesarios para el test.
  • ACT: Ejecutamos el código a probar (SUT, Subject Under Test).
  • Assert: Verificamos que la salida del código es la esperada.

Unitarios, Integración y en medida de lo posible E2E

Estructura de un Test

Arrange

Usamos esta sección para configurar el contexto donde se ejecutará la prueba.

La suite de pruebas proporcionan funciones adicionales para facilitar el ARRANGE.

Arrange

ACT

Ejecutamos el código a probar.

El test debe reflejar cómo se usará el código en producción.

Evitar el tercer usuario. (Usuario, Desarrollador, Tester).

No perder el FOCO! La prueba sirve para darnos confianza en nuestro código, no para comprobar el código de terceros!

Evitar probar detalles de implementación, o será una prueba débil.

Assert

Verificamos que la salida de la prueba es la esperada.

Comprobar que un método se comporta cómo se espera:

El método devuelve el valor esperado.

El método es llamado con los parámetros adecuados.

Un elemento del método es usado de forma correcta.

...

Assert

Cada suite nos proporciona herramientas para realizar estas verificaciones.

Assert

Mocks

Nos permiten aislarnos de otras unidades de código o de otros sistemas incluidos en nuestro software.

  • Se usan sobretodo en pruebas unitarias.
  • Aceleran la ejecución de las pruebas.
  • Permiten centrar la prueba en el comportamiento de nuestro código.
  • Permiten realizar pruebas que de otra forma serían muy costosas.
  • Pueden suponer una fuente de pérdida de confianza en la prueba.

Mocks

  • Dummy: Los objetos se pasan pero nunca se usan. Por lo general, sólo se utilizan para rellenar las listas de parámetros.
  • Fake: Los objetos tienen implementación, pero no es la usada en producción, un buen ejemplo es una base de datos en memoria.
  • Stubs: Proporciona respuestas preconfiguradas a las llamadas realizadas durante los tests, por lo general no responde en absoluto a nada fuera de lo que está programado para el test.
  • Spies: Son “Stubs” que también registran cierta información de como y cuanto han sido llamados. Una forma de Spy podría ser un servicio de correo electrónico que registra cuántos mensajes se enviaron.
  • Mocks: Son objetos preprogramados con las respuestas esperadas, que forman una especificación de las llamadas que se espera que reciban (API completa).

Mocks

Elemento a testear!!

Test para verificar la función “rm”

Mocks

Elemento a testear!!

Test para verificar la función “rm”

Mocks

Mockear API de terceros, como la de Facebook!!

Mocks

Mocks

Creamos sustitutos a partir de Interfaces:

Mocks

Configuramos los valores devueltos por los sustitutos:

Cualquier parámetro

Mocks

Ejemplo de Test Unitario

Ejemplo de Test Integración

Ejemplo de Test E2E

Dependiendo del test podemos realizarlos con las herramientas de pruebas unitarias.

Ejemplo de Test E2E

Por norma general es mejor usar herramientas específicas.

Test UI

Se encargan de probar la UI.

¿Qué, Cuánto?

Respuesta típica tópica: Depende del proyecto!.

Pistas:

100% coverage != 100% confianza.

Pruebas débiles se rompen con facilidad.

Pruebas de flujos que no se ejecutarán jamás.

Código muy cambiante es difícil de mantener sus pruebas. ¿UI?

¿Qué, Cuánto?

¿Qué, Cuánto?

¿Mockear?

Procesos que no sean fiables y/o consumen mucho tiempo.

  • Accesos a ficheros: Siempre.
  • Peticiones HTTP: Siempre.
  • Acceso a Datos (Persistencia): BBDD en memoria (Fake) + Mock/Stub.
  • Flujos complejos que de otra manera serían muy difíciles de reproducir: Mock/Stub/Spy.
  • Flujos complejos que requieren de un tercero para completarse: Stub/Spy.

Mockear puede suponer una pérdida de confianza, siempre hay que ser muy cuidadoso cuando apliquemos un mock!.

¿Qué, Cuánto?

Copa de Test de Kent C. Dodds

¿Qué, Cuánto?

Copa de Test de Kent C. Dodds

Cypress

UnitTest

Library

Linter

Mock

Doubles

¿Cuándo? Flujo de desarrollo

¿Cuándo?

¿Cuándo?

¿Cuándo?

Feature

Devel

Release

Master

Test Unit/Integ

devel.domain

beta.domain

PRODUCCIÓN

Test Unit/Integ

Test Unit/Integ + e2e

Test Unit/Integ + e2e + Humano

PR

PR

HOTFIX

Test todo lo humanamente posible

¿Cuándo? ¡Cuanto antes mejor!

¿Cuándo? ¡En cada sprint es una buena meta!

¿Cómo empiezo?

Añadir Test/TDD a la cultura del equipo.

  • Formación
  • Proyectos secundarios
  • Hackathon
  • Charlas internas

Establecer procesos de Code Review. (Usar test cómo documentación)

En proyectos nuevos, plantear la estrategia de TDD desde el principio.

En proyectos iniciados:

  • Plantear pruebas por cada error que aparezca.

  • Empezar con unas pocas pruebas E2E

  • Refactorizar las pruebas E2E en pruebas Unitarias/Integración

Recursos

Recursos

Recursos

Recursos

Charla Iniciación Testing - Google Slides