Llevas todo el curso testeando, aunque no lo llamaras así. Cada vez que guardabas un cambio, abrías el navegador, pulsabas un botón y mirabas si pasaba lo que esperabas, estabas probando tu código a mano. Funciona con una página y tres botones. No funciona con un motor de datos, diez funciones encadenadas y un equipo que toca el mismo fichero cada día: nadie va a reabrir y reclicar la app entera tras cada cambio. Ahí entra el testing: que esa comprobación la haga el ordenador, igual cada vez, en segundos.
Qué es un test, de verdad#
Un test es código que ejercita otro código y comprueba que el resultado es el que esperas. Dicho de otra forma: es una especificación ejecutable. No es un comentario que describe lo que la función debería hacer y se queda viejo en silencio; es código que lo comprueba y se queja en voz alta en cuanto deja de cumplirse.
Para que tengas una imagen concreta, así se ve un test del motor del Team Builder. No te
preocupes por la sintaxis: cada pieza (describe, it, expect) la desmenuzamos en el capítulo
Anatomía de un test. Léelo como se lee una frase:
// "describe" agrupa los tests de una misma pieza bajo un título.
describe('enriquecer', () => {
// "it" declara UN caso concreto, descrito en lenguaje llano.
it('calcula el winrate como victorias entre partidas', () => {
// preparamos un héroe de ejemplo: 6 victorias de 10 partidas.
const heroe = { nombre: 'Genji', rol: 'Daño', partidas: 10, victorias: 6 };
// ejecutamos la función que queremos probar.
const resultado = enriquecer([heroe]);
// "expect" afirma lo que debe pasar: 6/10 = 60% de winrate.
expect(resultado[0].winrate).toBe(60);
});
});Se lee casi como español: describe enriquecer: it calcula el winrate como victorias entre partidas; espero que el winrate sea 60. Si un día alguien cambia la fórmula y el winrate sale mal, este test pasa de verde a rojo y te dice exactamente qué caso ha dejado de cumplirse.
La red que los tipos no cubren#
En el Nivel 5 añadiste TypeScript al motor: una red de seguridad que caza errores de forma antes de ejecutar. Si intentas dividir un número entre un texto, o leer un campo que no existe, el compilador te frena. Eso es enorme, pero tiene un límite claro.
Mira la función del ejemplo. Si en vez de victorias / partidas escribieras partidas / victorias, los tipos encajan igual: sigues dividiendo un número entre otro número. TypeScript
compila sin una queja. Y sin embargo el winrate sale al revés: un héroe que gana el 60% aparecería
con un 167%. Los tipos verifican que las piezas encajan; no verifican que el resultado sea
correcto. Esa segunda red es la del testing.
Por eso tipos y tests no compiten: se complementan. Los tipos cazan “esto no encaja”; los tests cazan “esto encaja pero está mal”. Un proyecto serio lleva las dos.
¿Y qué pasa si no testeas? El coste de verdad#
Es tentador pensar que testear es tiempo que no dedicas a “avanzar”. Mira el otro lado: el coste de un bug crece con el tiempo que tarda en descubrirse.
- Lo cazas mientras escribes: lo arreglas en segundos, nadie se entera.
- Se cuela hasta la revisión de código de un compañero: ahora le roba tiempo a otra persona y hay que ir y volver.
- Llega a producción: ya ha afectado a usuarios reales. Toca investigar qué pasó, reproducirlo, parchearlo y desplegar con prisa —y, en un banco, quizá explicar por qué un saldo salió mal—.
El mismo fallo, según dónde se descubra, va de un retoque trivial a una incidencia con gente mirando el reloj. Los tests no eliminan los bugs, pero mueven el momento en que los encuentras hacia la izquierda, cuando arreglar es barato y silencioso.
Y hay un segundo regalo, el que más se nota en el día a día: refactorizar sin miedo. Refactorizar es cambiar el código por dentro sin cambiar lo que hace. Sin tests, cada cambio es a ciegas: tocas algo y rezas. Con una suite que fija el comportamiento, reescribes una función entera y, si rompes algo, un test se pone en rojo al instante —no tres semanas después por boca de un usuario—. Esa es la libertad que compras: tocar el código con la red puesta.
El mapa: tres niveles de test#
No todos los tests son iguales. Se ordenan en tres niveles según cuánto abarcan, y conviene tener el mapa entero desde el principio aunque en este nivel solo pisemos el primero. Con el Team Builder:
- Test unitario. Prueba una pieza aislada, normalmente una función sola. Por ejemplo:
enriquecer, por sí sola, calcula bien el winrate de un héroe. Es el test más rápido y barato, y el que más tendrás. La base de la pirámide. - Test de integración. Prueba que varias piezas funcionan juntas. Por ejemplo: encadenar
enriquecer→filtrarPorRol→rankearPorWinratedevuelve los héroes de un rol ordenados por winrate. Cada función ya funcionaba sola; aquí compruebas que encajan entre ellas. - Test end-to-end (e2e). Prueba la app entera como la usaría una persona: abrir el Team Builder en un navegador real, escribir “Genji” en el buscador, pulsar y comprobar que aparece su carta. Es el más realista y también el más lento y frágil. La cúspide.
La idea clásica (la pirámide de tests) es tener muchos unitarios, algunos de integración y unos pocos e2e: cuanto más arriba, más caro y más lento de mantener. En 2026 hay matices a esa forma —los verás en el Nivel 8, donde el testing vuelve aplicado a React—, pero la intuición se sostiene: la mayoría de tu seguridad la dan tests pequeños y rápidos sobre piezas pequeñas.
Qué vamos a hacer en este nivel#
Este nivel se queda, a propósito, en el primer escalón y medio: tests unitarios y de integración sobre lógica pura —el motor del Team Builder que ya tipaste—, con la herramienta estándar del ecosistema, Vitest. Nada de componentes, nada de asincronía, nada de simular dependencias todavía: eso llega en el Nivel 8, cuando tengas React delante y el testing tenga que lidiar con el DOM y con la red. Aquí construyes la base: entender qué es un test, escribirlo bien y cogerle el gusto a la red de seguridad.
Comprueba lo que sabes#
Pregunta 1 de 5