Test Unitarios con Deno
¿Qué es BDD?
BDD (Behavior-Driven Development) es una metodología de desarrollo que coloca el comportamiento del software en el centro del proceso. A diferencia del testing unitario tradicional que se enfoca en “¿qué hace esta función?”, BDD se pregunta “¿cuál es el comportamiento que espera el usuario o el negocio?”.
En BDD, los tests se escriben usando una estructura clara y legible:
- Given (Dado): El contexto o estado inicial.
- When (Cuando): La acción que realizamos.
- Then (Entonces): El resultado esperado.
Esta estructura hace que los tests sean casi documentación viva del sistema. No solo validan que el código funciona, sino que también comunican por qué y cómo debe comportarse.
Fortalezas de BDD
- Claridad: Los tests se leen como especificaciones. Cualquiera (técnico o no) puede entender qué se está probando.
- Documentación actualizada: El comportamiento del código siempre está documentado en los tests; no se queda obsoleto como un README abandonado.
- Colaboración efectiva: Diseñadores, QA y desarrolladores pueden discutir el comportamiento esperado usando el mismo lenguaje.
- Menos bugs por ambigüedad: Al escribir primero el comportamiento esperado, se reducen las interpretaciones erróneas.
- Refactoring seguro: Con tests BDD claros, puedes modificar la implementación sin miedo a romper el comportamiento.
Por qué BDD en Deno
Deno nació con premisas fuertes en seguridad, modernidad y simplicidad. No sorprende que su sistema de testing incorpore características que se alinean perfectamente con BDD:
- Sistema de testing built-in sin dependencias externas (no necesitas instalar nada adicional).
- Sintaxis moderna con
describe()eit()para expresar comportamiento. - Seguridad de permisos por defecto (los tests se ejecutan en un sandbox; solo permites lo que necesitas).
- TypeScript out-of-the-box sin configuración.
Esto convierte a Deno en una plataforma ideal para practicar BDD sin fricción.
Iniciemos un proyecto de prueba
Crearemos esta estructura de directorios para ir creando los archivos necesarios para una prueba simple.
calc-project/ |
El contenido del archivo deno.json es el siguiente. Recuerda que en este archivo es donde se declaran las dependencias y las tareas ejecutables.
1 | { |
Ahora revisemos el contenido de los archivos del proyecto. El primero es una clase con 3 operaciones matemáticas simples: suma, resta y división.
1 | /** |
A continuación, veremos cómo se implementan los tests unitarios sobre la clase Calc usando el estilo BDD que nos ofrece Deno y las dependencias de @std/testing y @std/expect.
1 | import { expect } from "@std/expect/expect"; |
Para ejecutar todos los tests, usamos el comando deno test. Este buscará y correrá todos los archivos de test en el proyecto, generando una salida similar a la siguiente:
1 | running 4 tests from ./test/Calc.test.ts |
En este bloque de código, estamos definiendo la estructura de nuestros tests utilizando el estilo BDD que nos proporciona Deno:
describe("Test unitarios sobre la clase Calc", ...): Este es el bloque principal que agrupa todos los tests relacionados con nuestra claseCalc. Funciona como un contenedor o una suite de pruebas.describe("sum - casos adicionales (BDD)", ...): Dentro de la suite principal, creamos un sub-grupo específico para las pruebas del métodosum. Esto ayuda a organizar y contextualizar los tests.it("suma números positivos", ...): Aquí definimos un caso de prueba concreto. La descripción"suma números positivos"deja claro cuál es el comportamiento que estamos validando.- Dentro del
it, creamos una instancia deCalc. - Usamos
expect(calc.sum(2, 3)).toEqual(5);para afirmar que el resultado de llamar asum(2, 3)es igual a5. La funciónexpectviene de la librería@std/expecty nos ofrece una forma legible y expresiva de hacer aserciones.
- Dentro del
describe("subtract - casos adicionales (BDD)", ...): De manera similar, creamos otro sub-grupo para el métodosubtract, manteniendo nuestros tests bien organizados.describe("div - validaciones", ...): Finalmente, un grupo para el métododiv. Aquí se incluyen dos casos de prueba interesantes:it("debería fallar dividiendo por 0", ...): Este test verifica que el código maneja los errores correctamente. Usamosexpect(() => calc.div(1, 0)).toThrow(...)para asegurar que, al intentar dividir por cero, se lance un error con el mensaje esperado. Nota que la llamada a la función que debe fallar se envuelve en una función flecha() => ....it("debería dividir correctamente 8/2=4", ...): Un test para el “camino feliz” o el caso de uso normal, asegurando que la división funciona como se espera.
Esta estructura jerárquica con describe e it no solo ejecuta el código, sino que también lo documenta de una manera que es fácil de leer y entender para cualquier persona en el equipo.
Ahora, profundicemos en cómo se estructuran y ejecutan los tests. La función describe es fundamental, ya que actúa como un agrupador que define un ámbito o scope para un conjunto de pruebas relacionadas. Dentro de este ámbito, podemos usar “hooks” (funciones especiales) para controlar el ciclo de vida de nuestros tests.
Estos son los hooks principales:
beforeAll: Se ejecuta una sola vez antes de que comiencen todos los tests dentro de sudescribe. Es ideal para preparar un estado inicial que no cambiará, como levantar un servidor o conectar a una base de datos de prueba.beforeEach: Se ejecuta antes de cada test (it) dentro de sudescribe. Perfecto para resetear el estado entre pruebas, como limpiar una tabla de la base de datos o crear una nueva instancia de una clase.afterEach: Se ejecuta después de cada test (it). Se usa para tareas de limpieza que deben ocurrir después de cada prueba, como borrar archivos temporales o cerrar una conexión.afterAll: Se ejecuta una sola vez después de que todos los tests dentro de sudescribehayan finalizado. Ideal para la limpieza final, como detener el servidor o cerrar la conexión a la base de datos.
La magia ocurre cuando anidamos bloques describe, ya que los hooks del ámbito exterior también se aplican a los ámbitos interiores.
Para ilustrar esto, veamos el siguiente código de ejemplo:
1 | import { afterAll, afterEach, beforeAll, beforeEach, describe, it } from "@std/testing/bdd"; |
La salida de esta ejecución revela el orden exacto en que Deno ejecuta cada bloque. Desglosemos lo que sucedió:
Test - scope y hooks ... |
- Inicio del Scope Padre: Se ejecuta
beforeAlldel scope padre (Before All 1). - Ejecución del primer test:
- Se ejecuta
beforeEachdel padre (Before Each 1). - Se ejecuta el cuerpo del
Test 1. - Se ejecuta
afterEachdel padre (After Each 1).
- Se ejecuta
- Inicio del Scope Anidado:
- Se ejecuta el
beforeAlldel scope anidado (Before All 2).
- Se ejecuta el
- Ejecución del segundo test (anidado):
- Se ejecuta
beforeEachdel padre (Before Each 1), porque el test anidado está dentro de su ámbito. - Se ejecuta
beforeEachdel scope anidado (Before Each 2). - Se ejecuta el cuerpo del
Test 2. - Se ejecuta
afterEachdel scope anidado (After Each 2). - Se ejecuta
afterEachdel padre (After Each 1).
- Se ejecuta
- Fin del Scope Anidado: Se ejecuta
afterAlldel scope anidado (After All 2). - Fin del Scope Padre: Se ejecuta
afterAlldel scope padre (After All 1).
Como puedes ver, la función describe no solo agrupa tests, sino que crea una jerarquía. Los hooks del describe padre “envuelven” a los hooks y tests de los describe hijos, permitiendo crear configuraciones y limpiezas complejas y ordenadas. Esto es clave para escribir tests mantenibles y escalables.
Palabras al Cierre
Espero que esta guía te haya dado una buena base para empezar a escribir tests unitarios robustos y expresivos en Deno usando BDD. Esta metodología no solo mejora la calidad de tu código, sino que también ayuda a que otros desarrolladores entiendan rápidamente el objetivo de cada test y lo que se busca lograr.
Si hay algún otro tema sobre Deno o testing que te gustaría que explorara, ¡déjamelo saber en los comentarios!
Referencias
Aquí tienes algunos enlaces para profundizar en los conceptos que hemos cubierto:
- Deno Manual - Testing: La documentación oficial de Deno sobre cómo escribir y ejecutar tests.
- Deno Standard Library - BDD: La documentación del módulo de BDD que permite usar la sintaxis
describeeit. - Deno Standard Library - Expect: Documentación de la librería de aserciones
expect, para validaciones de estilo Jest. - ¿Qué es BDD? (Cucumber.io): Una excelente introducción a los principios y prácticas de Behavior-Driven Development por parte de uno de los referentes en el área.
Test Unitarios con Deno
https://blog.pcollaog.cl/2025/10/31/Test-Unitarios-con-Deno/