Pruebas Efectivas de Creación de Usuarios en POS con Bases de Datos

Clase 14 de 25Curso de End to End Testing para APIs REST con Node.js

Contenido del curso

Pruebas a la API de Fake Store

Pruebas en Entornos de Desarrollo Avanzados

Resumen

Cuando ejecutas pruebas sobre endpoints que crean registros en la base de datos, existe un problema silencioso que puede hacer que tus tests pasen la primera vez y fallen la segunda. Entender por qué ocurre esto y cómo abordarlo es fundamental para construir un conjunto de pruebas end-to-end confiable y repetible.

¿Cómo se construye una prueba POST para crear usuarios?

El punto de partida es el endpoint API/v1/users, que recibe un email y un password para crear un nuevo usuario. Si los datos son inválidos, responde con un código 400 (bad request); si son válidos, retorna un 201 con el ID y los datos del usuario creado [01:00].

Partiendo de las pruebas que ya existían para la capa de validación de datos, se replica la estructura y se ajusta para enviar datos válidos:

  • Se define un email correcto, por ejemplo pepito@mail.com.
  • Se asigna un password válido como pepito123.
  • Se espera que el endpoint responda con un status 201.

Pero la prueba no termina ahí. Según la lógica de negocio, cada usuario creado por este endpoint recibe automáticamente el rol de administrador. Entonces se añaden verificaciones contra la base de datos [02:30]:

  • Se busca el usuario recién creado por su ID usando models.
  • Se valida que el usuario exista con el matcher toBeTruthy.
  • Se comprueba que el rol asignado sea admin.
  • Se verifica que el email almacenado coincida exactamente con el enviado en el request.

Este último punto es importante: no debería existir ninguna transformación inesperada del email entre lo que se envía y lo que se guarda.

¿Por qué las pruebas fallan la segunda vez que se ejecutan?

Al correr las pruebas por primera vez, todo funciona perfectamente. Pero al ejecutarlas de nuevo, aparece un error con código 409 (conflict) [03:45].

El código 409 indica que se está intentando crear un usuario que ya existe en la base de datos. Esto tiene total sentido desde la lógica de negocio: no se pueden duplicar usuarios. Si desde Insomnia se envía el mismo POST con el mismo email, también se obtiene un 409.

El problema de fondo es el estado persistente en la base de datos. La primera ejecución crea al usuario pepito@mail.com; la segunda intenta crearlo de nuevo y falla porque ya está registrado.

¿Es válido usar emails aleatorios para evitar conflictos?

Una solución tentadora sería generar un email aleatorio con algo como Math.random() para que nunca se repita [04:50]. Sin embargo, no es una buena práctica. Las pruebas deben ser deterministas y predecibles, no depender de valores aleatorios que dificulten la depuración.

¿Qué sucede si se elimina manualmente el registro?

Para confirmar la causa del fallo, se puede conectar directamente al contenedor de Docker con PostgreSQL y explorar la base de datos [05:20]. Al ejecutar un SELECT sobre la tabla de usuarios, se ven todos los registros creados, incluyendo el usuario de prueba.

Si se elimina manualmente ese registro con un DELETE por ID, las pruebas vuelven a pasar sin problema. Pero al ejecutarlas una vez más, el ciclo se repite: el usuario se crea, queda almacenado y la siguiente ejecución falla [06:10].

¿Cuál es la solución correcta para pruebas end-to-end con base de datos?

El comportamiento esperado de cualquier suite de pruebas, ya sean unit tests o pruebas end-to-end, es que siempre produzcan el mismo resultado sin importar cuántas veces se ejecuten. Que una prueba pase la primera vez y falle la segunda es señal de que algo está mal en la configuración del entorno de pruebas [03:30].

Lo que se necesita es una base de datos que no guarde estado entre ejecuciones. Esto significa que cada vez que se corra el comando npm run end-to-end, el entorno debe partir desde cero, sin datos residuales de ejecuciones anteriores.

Para lograr esto existe una técnica especial ampliamente utilizada en pruebas end-to-end que requieren conexión a bases de datos: trabajar con una base de datos aislada que se reinicie automáticamente antes de cada ejecución.

Si has experimentado este tipo de fallos intermitentes en tus pruebas, comparte cómo los has resuelto en los comentarios.