Qué es TDD (Test Driven Development): ciclo y ejemplo
TDD, o desarrollo dirigido por tests, le da la vuelta al orden habitual de programar: primero escribes cómo sabrás que algo funciona y después lo haces funcionar. Sin tests, los fallos se descubren tarde: al probar a mano, en la revisión o, peor, en producción.
Es como un sastre que toma una medida antes de cada corte y prueba el traje en cada paso. Las medidas son los tests; cortar es escribir el código; y ajustar las costuras sin cambiar la talla es el refactor. El símil tiene un límite: el traje solo será tan bueno como las medidas que tomes. Un test que no existe no te avisa de nada.
Qué es TDD
TDD (Test Driven Development) es una técnica de diseño e implementación de software. En español también lo verás como desarrollo guiado por pruebas o desarrollo basado en pruebas: son traducciones distintas de lo mismo.
Forma parte de las prácticas de Extreme Programming (XP). Martin Fowler, en su entrada Test Driven Development, sitúa su origen en Kent Beck, a finales de los años noventa, como parte de XP. La referencia clásica es el libro de Beck Test-Driven Development: By Example (2002).
La idea cabe en una frase: no escribes código nuevo sin tener antes un test que falle y que ese código haga pasar.
Un test, aquí, es un pequeño programa que usa tu código con unos datos concretos y comprueba que el resultado es el esperado. Por ejemplo: «si la compra es de 50 €, el envío cuesta 0 €».
Por eso hay quien lo llama diseño dirigido por ejemplos: cada test es un ejemplo concreto de cómo debe comportarse el programa. También verás «Test Driven Design».
¿Es TDD una metodología?
Se busca mucho como «metodología TDD», pero es más preciso llamarlo técnica o práctica. Una metodología, como Scrum o el propio XP, organiza todo el trabajo de un equipo: cómo se planifica, cómo se entrega o cómo se reparten los roles. TDD es más pequeño y más concreto: dice cómo escribir cada trozo de código. Puedes usarlo dentro de cualquier metodología. Si lo que buscas es cómo implantarlo en un proyecto, lo tienes en metodología TDD paso a paso.
TDD no es lo mismo que hacer tests
Muchos equipos tienen tests y no hacen TDD. La diferencia no está en si hay tests, sino en cuándo se escriben y para qué.
| Tests después del código | TDD (tests antes) | |
|---|---|---|
| Cuándo se escribe el test | Cuando el código ya funciona | Antes de escribir el código que lo cumple |
| Qué comprueba | Lo que el código ya hace | Lo que el código debería hacer |
| Qué aporta al diseño | Poco: la forma del código ya está decidida | Mucho: obliga a pensar cómo se va a usar antes de escribirlo |
| Riesgo típico | Partes sin cubrir, porque «ya funcionaba» | Avanzar despacio al principio, mientras se coge práctica |
Vuelve al sastre. Medir después de cortar solo sirve para comprobar si la tela se ha quedado corta, y la tela cortada no se puede descortar. Medir antes de cada corte cambia la forma de cortar.
Fowler lo explica en la misma entrada: como solo escribes código para hacer pasar un test, acabas con código que se prueba a sí mismo (self-testing code), y pensar primero en el test te obliga a pensar primero en la interfaz, es decir, en cómo se va a llamar ese código.
En TDD se suele trabajar con pruebas de unidad. Una prueba de unidad es un test pequeño y rápido que comprueba una unidad, es decir, un comportamiento pequeño, a menudo una función o una clase. Tienes qué es y cómo se escribe una buena en Pruebas de unidad en código limpio, y las partes de un test, en Composición de un test en TDD.
El ciclo TDD: rojo, verde, refactor
- Rojo. Escribe un test pequeño para algo que tu código todavía no hace. Ejecútalo y comprueba que falla.
- Verde. Escribe el código mínimo para que ese test pase, aunque sea poco elegante.
- Refactor. Mejora el código (nombres, duplicados, estructura) sin cambiar lo que hace. Los tests deben seguir en verde.
Y vuelta a empezar con el siguiente ejemplo. Cada vuelta dura minutos, no horas.
Los colores vienen de las herramientas de tests, que pintan en rojo lo que falla y en verde lo que pasa. La fórmula rojo, verde y refactor viene ya del libro de Kent Beck Test-Driven Development: By Example (2002), y Beck la sigue usando, «Red → Green → Refactor», en las instrucciones que da a un agente de IA en su artículo Augmented Coding: Beyond the Vibes (2025).
La versión de Kent Beck, en cinco pasos
En su artículo Canon TDD (2023), Beck describe el flujo con más detalle. En traducción propia:
- Escribe una lista de los escenarios de prueba que quieres cubrir.
- Convierte exactamente un elemento de la lista en un test real, concreto y ejecutable.
- Cambia el código para que ese test (y todos los anteriores) pase, añadiendo a la lista los casos nuevos que descubras.
- Si lo necesitas, refactoriza para mejorar el diseño de la implementación.
- Mientras la lista no esté vacía, vuelve al paso 2.
Fíjate en el primer paso: antes de programar, apuntas qué casos quieres cubrir. Esa lista será muy útil más adelante, cuando el que programe sea un agente de IA.
Un ejemplo de TDD paso a paso
Vamos a programar una regla de una tienda online: las compras de 50 € o más no pagan envío; las demás pagan 4,99 €.
Usaremos JavaScript con Node.js 24 y su ejecutor de tests integrado, node:test. No hace falta instalar nada más. Todas las salidas que verás son reales; solo se han quitado las líneas de la traza del error y algunos contadores para que se lean mejor.
Primero, la lista de casos (el paso 1 de Beck):
- Una compra de 50 € no paga envío.
- Una compra de menos de 50 € paga 4,99 €.
Crea una carpeta con un package.json que solo diga que usamos módulos de JavaScript modernos:
{ "type": "module" }
1. Rojo: el primer test falla
Escribimos el primer caso de la lista en envio.test.js:
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { costeEnvio } from './envio.js';
test('una compra de 50 € no paga envío', () => {
assert.equal(costeEnvio(50), 0); // esperamos 0 € de envío
});
Para que el test pueda ejecutarse, creamos envio.js con la función vacía:
export function costeEnvio(totalCompra) {}
Ejecutamos los tests. node --test busca, entre otros, los ficheros cuyo nombre termina en .test.js:
node --test
✖ una compra de 50 € no paga envío (1.292627ms)
ℹ tests 1
ℹ pass 0
ℹ fail 1
✖ failing tests:
test at envio.test.js:5:1
✖ una compra de 50 € no paga envío (1.292627ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
undefined !== 0
Rojo. Y falla por el motivo correcto: esperábamos 0 y la función no devuelve nada (undefined). Ver fallar el test importa: así sabes que de verdad comprueba algo.
2. Verde: lo mínimo para que pase
¿Qué es lo mínimo que hace pasar este test? Devolver 0:
export function costeEnvio(totalCompra) {
return 0;
}
✔ una compra de 50 € no paga envío (0.697051ms)
ℹ tests 1
ℹ pass 1
ℹ fail 0
Verde. Sí, parece trampa: la función siempre devuelve 0. Es a propósito. Solo escribes el código que te piden los tests; el siguiente test obligará a hacerlo mejor.
3. Rojo otra vez: el segundo caso
Añadimos el segundo elemento de la lista:
test('una compra de menos de 50 € paga 4,99 € de envío', () => {
assert.equal(costeEnvio(49.99), 4.99);
});
✔ una compra de 50 € no paga envío (0.818209ms)
✖ una compra de menos de 50 € paga 4,99 € de envío (0.875729ms)
ℹ tests 2
ℹ pass 1
ℹ fail 1
✖ failing tests:
test at envio.test.js:9:1
✖ una compra de menos de 50 € paga 4,99 € de envío (0.875729ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
0 !== 4.99
El primer test sigue en verde; el nuevo falla porque la función devuelve 0 y esperábamos 4.99.
4. Verde: ahora sí, la regla
export function costeEnvio(totalCompra) {
if (totalCompra >= 50) {
return 0;
}
return 4.99;
}
✔ una compra de 50 € no paga envío (0.920215ms)
✔ una compra de menos de 50 € paga 4,99 € de envío (0.254107ms)
ℹ tests 2
ℹ pass 2
ℹ fail 0
5. Refactor: ordenar sin cambiar lo que hace
Funciona, pero 50 y 4.99 son números mágicos: valores sueltos que no dicen qué significan. Les damos nombre:
const ENVIO_GRATIS_DESDE = 50;
const COSTE_ENVIO = 4.99;
export function costeEnvio(totalCompra) {
if (totalCompra >= ENVIO_GRATIS_DESDE) {
return 0;
}
return COSTE_ENVIO;
}
✔ una compra de 50 € no paga envío (0.972865ms)
✔ una compra de menos de 50 € paga 4,99 € de envío (0.152743ms)
ℹ tests 2
ℹ pass 2
ℹ fail 0
Todo sigue en verde: el código se lee mejor y hace exactamente lo mismo. Si mañana el envío gratis empieza en 60 €, sabes qué línea cambiar.
La red de seguridad, en acción
¿Y si al refactorizar te equivocas? Prueba a cambiar >= por >, un despiste fácil de cometer:
✖ una compra de 50 € no paga envío (1.300443ms)
✔ una compra de menos de 50 € paga 4,99 € de envío (0.186037ms)
ℹ tests 2
ℹ pass 1
ℹ fail 1
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
4.99 !== 0
El test te avisa al momento: con ese cambio, una compra de justo 50 € pagaría envío. Esa tranquilidad para cambiar el código es lo que te dan los tests escritos antes.
Primero, cómo sabrás que funciona. Después, que funcione.
El mismo ejemplo de TDD en Java
TDD no depende del lenguaje. Este es el mismo ejemplo en Java 25 con JUnit 6, uno de los marcos de tests más usados en Java. Para no alargarlo, saltamos al momento en que ya hay dos tests y la función todavía devuelve siempre 0.
El test, en EnvioTest.java. Cada método marcado con @Test es un ejemplo:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class EnvioTest {
@Test
void unaCompraDe50NoPagaEnvio() {
assertEquals(0, Envio.coste(50));
}
@Test
void unaCompraDeMenosDe50Paga499() {
assertEquals(4.99, Envio.coste(49.99));
}
}
El código, en Envio.java, con lo mínimo que hacía pasar el primer test:
class Envio {
static double coste(double totalCompra) {
return 0;
}
}
Para no complicar el ejemplo, aquí y en JavaScript el dinero va en números decimales (double); en código real se usan céntimos (enteros) o BigDecimal, que no arrastran errores de redondeo.
Para ejecutarlo sin instalar Maven ni Gradle, basta con el JAR del lanzador de consola de JUnit (junit-platform-console-standalone-6.1.3.jar, en Maven Central). Se compila y se lanzan los tests:
javac -d out -cp junit-platform-console-standalone-6.1.3.jar *.java
java -jar junit-platform-console-standalone-6.1.3.jar execute \
--class-path out --select-class EnvioTest --details=tree
╷
├─ JUnit Platform Suite ✔
├─ JUnit Jupiter ✔
│ └─ EnvioTest ✔
│ ├─ unaCompraDeMenosDe50Paga499() ✘ expected: <4.99> but was: <0.0>
│ └─ unaCompraDe50NoPagaEnvio() ✔
└─ JUnit Vintage ✔
Failures (1):
JUnit Jupiter:EnvioTest:unaCompraDeMenosDe50Paga499()
=> org.opentest4j.AssertionFailedError: expected: <4.99> but was: <0.0>
Rojo, y por el motivo correcto: esperaba 4.99 y recibe 0.0. Escribimos la regla, todavía con los números tal cual:
class Envio {
static double coste(double totalCompra) {
if (totalCompra >= 50) {
return 0;
}
return 4.99;
}
}
╷
├─ JUnit Platform Suite ✔
├─ JUnit Jupiter ✔
│ └─ EnvioTest ✔
│ ├─ unaCompraDeMenosDe50Paga499() ✔
│ └─ unaCompraDe50NoPagaEnvio() ✔
└─ JUnit Vintage ✔
Verde. Ahora, el refactor: igual que en JavaScript, damos nombre a los números mágicos sin cambiar lo que hace el código.
class Envio {
private static final double ENVIO_GRATIS_DESDE = 50;
private static final double COSTE_ENVIO = 4.99;
static double coste(double totalCompra) {
if (totalCompra >= ENVIO_GRATIS_DESDE) {
return 0;
}
return COSTE_ENVIO;
}
}
╷
├─ JUnit Platform Suite ✔
├─ JUnit Jupiter ✔
│ └─ EnvioTest ✔
│ ├─ unaCompraDeMenosDe50Paga499() ✔
│ └─ unaCompraDe50NoPagaEnvio() ✔
└─ JUnit Vintage ✔
Sigue en verde. El ciclo es idéntico al de JavaScript; solo cambian la sintaxis y la herramienta. Si trabajas con IntelliJ, en Ejecutar todos los test JUnit del proyecto tienes cómo lanzarlos desde el editor, y en la Kata Stubs y Spies, un ejercicio de TDD en Java con dobles de prueba.
Herramientas para hacer TDD en cada lenguaje
Para TDD no necesitas ninguna herramienta especial: basta con una que ejecute tests en segundos y te diga cuál falla. Estas son algunas de las más usadas:
| Lenguaje | Herramientas |
|---|---|
| JavaScript y TypeScript | node:test (viene con Node), Jest y Vitest |
| Java | JUnit |
| Kotlin | JUnit o kotlin.test |
| Python | unittest (viene con Python) y pytest |
| Ruby | Minitest y RSpec |
| C# | xUnit.net y NUnit |
| PHP | PHPUnit |
Si empiezas, elige la que ya trae tu lenguaje o la que use tu equipo: lo que importa es el ciclo, no la herramienta. Tienes la instalación paso a paso en Instalar Jest y una introducción en Ruby en Introducción al testing en Ruby.
Las ideas de Carlos Blé
Si quieres profundizar en español, una buena lectura es Diseño Ágil con TDD, de Carlos Blé, el libro en el que se apoyaba la versión original de este artículo. Tienes una reseña en Libro TDD de Carlos Blé: Diseño Ágil con TDD.
Tienes cada paso del ciclo y sus reglas en Algoritmo TDD, y cómo empezar a usarlo en un proyecto real, en metodología TDD paso a paso.
Por qué usar TDD
Estas son las ventajas que se le suelen atribuir. Son fruto de la práctica, no de mediciones, así que tómalas como lo que la técnica busca, no como una garantía:
| Ventaja | Por qué ocurre |
|---|---|
| Evitas sobrediseñar | Escribir el ejemplo antes del código te obliga a programar solo lo necesario |
| Los tests documentan el código | Cada test explica, con un caso concreto, qué hace cada pieza |
| Descubres más casos en el diseño | Al pensar ejemplos aparecen situaciones que no habías contemplado |
| Cambias el código con confianza | Si algo se rompe, un test te avisa en segundos |
| Mejora el trabajo en equipo | Los tests son un lenguaje común: dicen qué se espera de cada pieza |
Inconvenientes de TDD
TDD también tiene costes, y conviene conocerlos antes de empezar. Este resumen es nuestro:
- Cuesta aprenderlo. Al principio vas más despacio: hay que acostumbrarse a pensar el ejemplo antes que la solución y a dar pasos pequeños. Las katas existen para practicar eso sin la presión de un proyecto real.
- Hay más código que mantener. Los tests también son código. Si están mal escritos, estorban tanto como cualquier otro código malo.
- Un test atado a los detalles frena el refactor. Si el test comprueba cómo está hecho algo en lugar de qué hace, se rompe con cada cambio interno aunque el comportamiento no cambie. La solución es probar el comportamiento visible, como hacen los tests del envío.
- No sustituye otras pruebas. TDD cubre comportamientos pequeños. Sigues necesitando pruebas de integración, de aceptación y, a veces, alguien que pruebe a mano.
Errores habituales
Beck enumera varios en Canon TDD. Estos son los que más afectan a quien empieza (resumen propio):
- Borrar comprobaciones para que el test «pase». Haz que pase de verdad.
- Copiar el resultado que da el código y pegarlo como valor esperado. Así el test confirma lo que hace el código, no lo que debería hacer.
- Mezclar el refactor con hacer pasar el test. Primero verde, después ordenar.
- Abstraer demasiado pronto. Para Beck, la duplicación es una pista, no una orden.
Y uno que no viene de esa lista, pero que se ve mucho: saltarse el refactor. Test, código, siguiente test… y el código se va ensuciando.
Otro que aparece justo en el refactor: tests que se rompen al cambiar cómo está hecho el código, aunque siga haciendo lo mismo. Por qué ocurre y cómo evitarlo, en tests frágiles.
TDD, BDD, ATDD y DDD: en qué se diferencian
Las siglas se parecen y se buscan juntas, pero no responden a la misma pregunta. Tres de ellas tratan de cómo guiar el desarrollo con ejemplos, a distinta escala; la cuarta trata de cómo modelar el negocio.
| Qué es | Quién lee los ejemplos | Escala | |
|---|---|---|---|
| TDD (Test Driven Development) | Escribir un test que falla antes de cada trozo de código | El equipo de desarrollo | Un comportamiento pequeño, a menudo una función o una clase |
| BDD (Behaviour Driven Development) | Casi lo mismo que TDD y ATDD, con otro vocabulario: comportamiento en vez de test, y escenarios «Dado… Cuando… Entonces…» | Desarrollo y negocio | Una funcionalidad |
| ATDD (Acceptance Test Driven Development) | Acordar con negocio los tests de aceptación antes de desarrollar una historia | Negocio, QA y desarrollo | Una historia de usuario |
| DDD (Domain-Driven Design) | Diseñar el software alrededor de un modelo del dominio del negocio | Todo el equipo, con el lenguaje del negocio | La arquitectura |
Algunas claves para no confundirlas:
- BDD cambia sobre todo el vocabulario. Se solapa mucho con TDD y ATDD: Dan North cuenta en Introducing BDD (2006) que empezó a hablar de «comportamiento» en lugar de «test» para evitar malentendidos. Lo tienes en qué es BDD.
- ATDD es un doble bucle. Primero se escribe un test de aceptación, que falla; después se hace pasar con varios ciclos de TDD por dentro. Steve Freeman y Nat Pryce lo describen así en el capítulo 1 de Growing Object-Oriented Software, Guided by Tests. Lo tienes en qué es ATDD.
- DDD no va de tests. El nombre viene del libro de Eric Evans de 2003, según Martin Fowler en su entrada Domain Driven Design. Se parece a TDD solo en las siglas: no compiten, y se pueden usar juntos. TDD te ayuda a escribir cada pieza; DDD, a decidir qué piezas hay y cómo se llaman.
Con el símil del sastre: TDD es tomar una medida antes de cada corte; BDD y ATDD, apuntar con el cliente cómo quiere que le quede el traje; DDD, conocer bien el oficio y su vocabulario, para que «sisa» signifique lo mismo para todos.
Si quieres ver cómo se combinan TDD y el diseño de la arquitectura, sigue con Inside-out TDD y outside-in TDD.
TDD cuando programa la IA
Con un agente de IA, el código ya no lo escribes tú, pero alguien tiene que decir qué debe hacer. En IA Limpia, el enfoque de Rubén para programar con IA, uno de los principios es «Sin pruebas, no está terminado»: primero se define qué debe pasar y después se pide el código.
Ahí TDD encaja de forma natural: los tests son el contrato que le das al agente.
Vuelve al sastre. Si el que corta es otro, y muy rápido, las medidas que has tomado dicen qué tiene que entregarte, y puedes comprobarlas una a una. Sin medidas, solo puedes mirar si «parece» que el traje queda bien.
Con tests como contrato
- Tú decides los casos: la lista de tests
- El agente hace pasar un test cada vez
- Sabes cuándo ha terminado: todo en verde
- Revisas el diff con una red de seguridad
Sin contrato
- El agente interpreta lo que has pedido
- Genera mucho código de una vez
- «Terminado» es lo que parezca terminado
- Revisas a ojo, sin saber qué puede romperse
Qué mirar en ese diff, paso a paso, está en cómo revisar código generado por IA.
En la práctica, el ciclo queda así:
- Tú escribes la lista de casos, igual que en el paso 1 de Beck. Es la parte que no conviene delegar: es donde decides qué debe hacer el programa.
- Escribes o revisas cada test antes de que el agente toque el código, y compruebas que falla.
- El agente hace pasar ese test con el mínimo código, sin modificar los tests.
- Se refactoriza con los tests en verde, y revisas el cambio antes de aceptarlo.
Una instrucción para el agente podría ser algo así:
Sigue el ciclo rojo, verde, refactor con la lista de casos de plan.md.
Toma el siguiente caso sin marcar, escribe su test y comprueba que falla.
Enséñame el test en rojo y espera mi visto bueno antes de implementar.
Después escribe solo el código necesario para que pase.
No modifiques ni borres tests existentes. Si crees que un test está mal, para y pregúntame.
Kent Beck trabaja de forma parecida en Augmented Coding: Beyond the Vibes: pide al agente que siga el ciclo de TDD a partir de una lista de tests en un fichero plan.md. Y entre las señales de alarma que vigila, cita que el agente haga trampa, por ejemplo desactivando o borrando tests. Es el mismo error de la lista anterior, solo que ahora lo comete una máquina, y muy deprisa.
El orden de esa lista también importa: ZOMBIES explica qué test escribir primero y cuál después.
Cuándo no encaja TDD
- Cuando aún no conoces la herramienta. Si es la primera vez que usas una librería, primero haz una prueba rápida para entenderla (en XP se llama spike) y luego vuelve a TDD. Más sobre los spikes en Algoritmo TDD.
- Cuando lo que quieres probar es cómo se ve algo, como el diseño de una pantalla. Ahí ayudan más otras pruebas.
El código antiguo sin tests no es un caso en el que TDD no encaje, pero no se empieza por ahí. Primero se escriben tests de caracterización, que fijan cómo se comporta hoy el código, y después se cambia con TDD. Michael Feathers lo explica en Working Effectively with Legacy Code.
TDD trabaja a nivel de comportamientos pequeños. Si quieres llevar la misma idea a los requisitos del negocio, con ejemplos que el cliente pueda leer, el siguiente paso es ATDD, desarrollo dirigido por tests de aceptación.
Tu primer reto
- Copia el ejemplo del envío y ejecútalo con
node --test. - Añade un caso nuevo a la lista: los clientes premium nunca pagan envío.
- Escribe su test, míralo fallar, hazlo pasar y refactoriza.
Cuando te salga solo, practica con ejercicios pensados para TDD en Katas para pruebas y TDD.
Fuentes
Consultadas el 7 y el 8 de noviembre de 2026.
- Kent Beck, Canon TDD (11 de diciembre de 2023): los cinco pasos y los errores habituales, en traducción y resumen propios.
- Kent Beck, Augmented Coding: Beyond the Vibes (25 de junio de 2025): la fórmula «Red → Green → Refactor», el fichero
plan.mdy la trampa de desactivar o borrar tests. - Kent Beck, Test-Driven Development: By Example, Addison-Wesley, 2002. Se menciona como referencia y como origen de la fórmula rojo, verde y refactor; no se cita su texto.
- Carlos Blé, Diseño Ágil con TDD (primera edición, 2010; página del libro en Leanpub). Se recomienda como lectura; no se le atribuyen ideas concretas.
- Steve Freeman y Nat Pryce, Growing Object-Oriented Software, Guided by Tests, Addison-Wesley, 2009, capítulo 1: el doble bucle de los tests de aceptación y los de unidad. Se menciona como referencia; no se cita su texto.
- Michael Feathers, Working Effectively with Legacy Code, Prentice Hall, 2004: los tests de caracterización. Se menciona como referencia; no se cita su texto.
- Martin Fowler, Test Driven Development (publicada en 2005, actualizada el 11 de diciembre de 2023): origen en Kent Beck y XP, y la relación entre escribir el test primero, el self-testing code y la interfaz. Resumen propio.
- Dan North, Introducing BDD (20 de septiembre de 2006; apareció antes en la revista Better Software, en marzo de 2006): el paso de «test» a «comportamiento» y la plantilla Given / When / Then. Resumen propio.
- Martin Fowler, Domain Driven Design (22 de abril de 2020): el origen del nombre en el libro de Eric Evans de 2003.
- Documentación oficial de JUnit 6.1.3: Console Launcher, con el comando
executey el JARjunit-platform-console-standalonepublicado en Maven Central. - Documentación oficial de Node.js 24: Test runner (
node:test), módulo estable; patrones de fichero que buscanode --testy reporterspecpor defecto. - El ejemplo de JavaScript se ha ejecutado con Node.js 24.21.0 en Ubuntu 26.04, sin dependencias. El de Java, con OpenJDK 25.0.5 (imagen oficial
eclipse-temurin:25) y JUnit 6.1.3, la última versión estable en Maven Central el 8 de noviembre de 2026. Las salidas son reales, recortadas para quitar la traza de los errores y algunos contadores.