TDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

  1. Inicio
  2. Blog
  3. Automatización de pruebas

Automatización de pruebas

TDD vs BDD: Diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

TDD ayuda a los desarrolladores a diseñar código correcto. BDD ayuda a todo el equipo a ponerse de acuerdo sobre lo que debe hacer el software. Vea la misma característica de descuento creada con cada enfoque y aprenda cómo ambos funcionan juntos.

9 min de lectura
TDD vs BDD: diferencias clave, una característica construida en ambos sentidos y cuándo usar cada uno

Puntos clave

  • TDD significa escribir primero una prueba fallida, luego solo el código suficiente para aprobar y luego ordenar.
  • BDD describe el comportamiento en un lenguaje compartido, generalmente como Dado, Cuándo, Entonces.
  • TDD guía principalmente el diseño de código. BDD construye principalmente un entendimiento compartido.
  • No son rivales y muchos equipos usan BDD para funciones y TDD para los detalles a continuación.

El debate TDD vs BDD a menudo se plantea como la elección de un bando. En realidad, responden a preguntas diferentes. El desarrollo basado en pruebas pregunta si el código hace lo que pretendía el desarrollador, mientras que el desarrollo basado en comportamiento pregunta si el equipo está de acuerdo sobre lo que el software debería hacer.

Para concretar la diferencia, creamos una pequeña función de descuento con cada enfoque. Ejecutamos el código en Python 3.13, usando la biblioteca estándar, y los resultados a continuación provienen de esa ejecución. La parte BDD utiliza un pequeño corredor propio para mostrar el mecanismo, por lo que un proyecto real usaría una herramienta como Cucumber o se comportaría en su lugar.

La respuesta corta

El desarrollo basado en pruebas (TDD) es una práctica de codificación. Escribe una pequeña prueba fallida, la hace pasar con el código más simple y luego mejora el diseño. Las pruebas están escritas en código y principalmente por desarrolladores. Kent Beck popularizó la práctica.

El desarrollo impulsado por el comportamiento (BDD) es una práctica de colaboración que surgió de TDD, y Dan North introdujo el término. Los desarrolladores, evaluadores y empresarios se ponen de acuerdo sobre ejemplos de cómo debería comportarse el sistema, escritos en un lenguaje sencillo, y esos ejemplos pueden luego automatizarse.

TDD vs BDD uno al lado del otro

Aspecto TDD BDD
Enfoque principal Código correcto y bien diseñado. Comprensión compartida del comportamiento.
Escrito en lenguaje de programación Lenguaje sencillo, como pepinillo.
Escrito por Desarrolladores Empresas, control de calidad y desarrolladores juntos
Legible por Desarrolladores Todos en el equipo
nivel típico Unidad Característica o aceptación
Punto de partida Una prueba fallida Una conversación con ejemplos.
ciclo Rojo, verde, refactor Descubra, formule, automatice
Herramientas comunes pytest, JUnit, broma Pepino, comportarse, SpecFlow, Reqnroll

la característica

Esta es la regla comercial que implementaremos: Los pedidos de 1000 o más obtienen un 10 % de descuento. Los miembros obtienen un 5 % de descuento adicional en esos pedidos.

Esto puede parecer claro, pero ya es ambiguo. ¿Un miembro que gasta 500 obtiene un 5 % de descuento? La frase dice “esas órdenes”, por lo que suponemos que no. Tenga esto en cuenta, porque este es exactamente el tipo de pregunta que BDD está diseñado para plantear tempranamente.

Construyéndolo con TDD

TDD sigue un bucle corto conocido como rojo, verde, refactor:

paso que haces
rojo Escriba una prueba para un comportamiento que aún no existe y observe cómo falla
Verde Escribe el código más simple que lo haga pasar.
Refactorizar Mejorar el código, manteniendo las pruebas verdes.

Estas son nuestras pruebas, con una para cada regla:

class DiscountTests(unittest.TestCase):
    def test_no_discount_below_1000(self):
        self.assertEqual(discount(999, False), 0)

    def test_ten_percent_from_1000(self):
        self.assertEqual(discount(1000, False), 100)

    def test_member_gets_extra_five_percent(self):
        self.assertEqual(discount(1000, True), 150)

Luego escribimos el código en tres etapas, ejecutando las pruebas después de cada una. Una sesión TDD estricta agrega una prueba a la vez y esto muestra la misma progresión:

Etapa 1: lo más sencillo

def discount(total, is_member):
    return 0

# 3 tests, 2 failed
#   test_member_gets_extra_five_percent
#   test_ten_percent_from_1000

Devolver cero parece una tontería, pero demuestra que las pruebas en realidad pueden fallar, y la única prueba que pasa es la regla de “sin descuento”.

Etapa 2: agregar el umbral

def discount(total, is_member):
    if total >= 1000:
        return total * 0.1
    return 0

# 3 tests, 1 failed
#   test_member_gets_extra_five_percent

Etapa 3: agregar miembros y limpiar

def discount(total, is_member):
    rate = 0.1 if total >= 1000 else 0
    if is_member:
        rate += 0.05
    return round(total * rate, 2)

# 3 tests, 0 failed

Pasan los tres. Pero lea atentamente esta versión. Le da a un miembro que gaste 500 un descuento del 5%, que no es lo que asumimos que significaba la regla. Ninguna prueba cubrió ese caso, por lo que nada lo marcó. TDD solo protege el comportamiento que pensaba probar. Esa es una limitación real, y la razón por la que las conversaciones sobre ejemplos son tan importantes.

Por qué es importante el ciclo

  • El rojo demuestra que la prueba funciona. Una prueba que nunca ha fallado podría no estar probando nada.
  • El color verde te mantiene concentrado. Escribes solo el código necesario, lo que ayuda a evitar el exceso de ingeniería.
  • Refactor mantiene alta la calidad. Las pruebas le brindan la confianza para cambiar el diseño de forma segura.
  • Influye en el diseño. El código que es difícil de probar suele estar demasiado estrechamente acoplado y se nota de inmediato.

Nuestro tutorial de pytest muestra una forma más conveniente de escribir pruebas como estas y el análisis de valores límite explica por qué elegimos 999 y 1000 como valores.

Construyéndolo con BDD

BDD comienza con una conversación, no con herramientas. A menudo se trata de una reunión breve conocida como los tres amigos, en la que una persona del producto, un desarrollador y un evaluador discuten ejemplos concretos:

Tester:  What about a member spending 500?
Product: Good question. No discount. It has to reach 1000 first.
Dev:     And exactly 1000 counts?
Product: Yes, 1000 or more.

Ese intercambio habría detectado el problema en nuestro código TDD. Luego registran sus ejemplos en un formato estructurado llamado Gherkin:

Feature: Order discounts

  Scenario: Member reaches the discount threshold
    Given a member with a cart worth 1000
    When they view the amount to pay
    Then the amount to pay is 850

  Scenario: Member below the threshold gets no discount
    Given a member with a cart worth 500
    When they view the amount to pay
    Then the amount to pay is 500
palabra clave Propósito
dado La situación inicial
cuando La acción o evento
entonces El resultado esperado

Cualquier miembro del equipo puede leer eso y decir “sí, eso está bien” o “no, eso está mal”. Incluso si nunca lo automatiza, el escenario ya ha realizado un trabajo útil.

Conexión de pasos al código

Las herramientas conectan cada línea en lenguaje sencillo con una función, llamada definición de paso. Para mostrar la idea, escribimos una pequeña versión nosotros mismos y ejecutamos el primer escenario:

@step("a member with a cart worth 1000")
def given(ctx):
    ctx["cart"] = Cart(is_member=True)
    ctx["cart"].add(1000)

@step("they view the amount to pay")
def when(ctx):
    ctx["amount"] = ctx["cart"].payable()

@step("the amount to pay is 850")
def then(ctx):
    assert ctx["amount"] == 850

# ok Given a member with a cart worth 1000
# ok When they view the amount to pay
# ok Then the amount to pay is 850

Las herramientas reales agregan parámetros, de modo que un solo paso pueda coincidir tanto con “1000” como con “500”, además de generar informes. El resultado es documentación viva: una descripción sencilla del sistema que falla estrepitosamente si deja de ser cierta.

Consejo: El valor de BDD radica en la conversación. Los equipos en los que una sola persona escribe Gherkin sola una vez finalizado el código obtienen el coste de la herramienta, pero casi ningún beneficio.

Escribir buenos escenarios

Débil mejor
Cuando hago clic en el botón con ID "btn-77" Cuando aplico el cupón
Entonces el resultado es correcto. Entonces el monto a pagar es 850
Veinte pasos en un escenario Un comportamiento por escenario
Describe la pantalla Describe la intención comercial.

Los escenarios que describen clics e ID de campos se interrumpen con cada rediseño y los lectores empresariales dejan de leerlos. Mantenga los detalles de la interfaz de usuario en el código de paso. Estos escenarios son primos cercanos de los ejemplos de caso de prueba frente a escenario de prueba y, a menudo, también se utilizan en pruebas de aceptación del usuario.

Usando ambos juntos

Los dos encajan naturalmente en un flujo de trabajo “de afuera hacia adentro”:

  1. El equipo se pone de acuerdo sobre el comportamiento y escribe un escenario BDD. Falla porque todavía no existe nada.
  2. Un desarrollador utiliza TDD para construir las unidades pequeñas necesarias.
  3. Las pruebas unitarias pasan y, eventualmente, también lo hace el escenario.
  4. Todo se ejecuta en su canal de CI/CD.

Mantenga cada uno en el nivel correcto. Debería tener algunos escenarios para comportamientos importantes y muchas pruebas unitarias rápidas para los detalles. Nuestra guía para pruebas unitarias versus pruebas de integración cubre el resto.

Herramientas

Idioma TDD (prueba unitaria) BDD
pitón pytest, prueba unitaria comportarse, pytest-bdd
javascript Broma, Vitest Cucumber.js
Java JUnit, PruebaNG Pepino-JVM
.NET xUnidad, NUnidad Registro de solicitudes, SpecFlow

Cuando usar cada

TDD encaja bien cuando:

  • Está escribiendo lógica compleja, como precios, análisis o permisos.
  • Estás arreglando un error, ya que puedes reproducirlo primero con una prueba fallida.
  • Estás trabajando en un código que cambiará con frecuencia.

BDD encaja bien cuando:

  • Las reglas comerciales son complejas y los malentendidos resultan costosos.
  • Las personas no técnicas realmente leerán y discutirán los escenarios.
  • Varios equipos necesitan una definición compartida de cómo se comporta algo.

Cualquiera de los dos puede ser excesivo cuando: estás escribiendo un prototipo desechable o explorando una idea técnica poco clara. Muchos desarrolladores primero aumentan y luego reescriben con pruebas. Las herramientas BDD también son una mala inversión si nadie fuera de ingeniería analiza los escenarios. En ese caso, las pruebas simples con buenos nombres son más sencillas.

Errores comunes

  • Tratar BDD como una herramienta de prueba. Pepino sin colaboración es solo una forma detallada de escribir pruebas.
  • Implementación de pruebas en TDD. Las pruebas vinculadas a detalles privados se interrumpen durante cada refactorización.
  • Omitir el paso de refactorización. Pasas pruebas además del código desordenado.
  • Escribir pruebas después del código y llamarlo TDD. Eso sigue siendo útil, pero se pierden los comentarios del diseño.
  • Escribir demasiados escenarios de interfaz de usuario. Estos se vuelven lentos y poco fiables. Consulte pruebas inestables.
  • Buscando cifras de cobertura. Una buena cobertura todavía pasa por alto comportamientos que nadie consideró, como muestra nuestro ejemplo.

Conclusión

TDD le ayuda a crear lo correcto y BDD le ayuda a crear lo correcto. Nuestro ejemplo de descuento mostró ambos lados: el código pasó todas las pruebas, pero una simple conversación reveló una suposición errónea. Pruébelo en su próxima función pequeña. Escriba tres ejemplos concretos con un colega antes de cualquier código y luego constrúyalo una prueba fallida a la vez.

Preguntas frecuentes

¿Cuál es la principal diferencia entre TDD y BDD?

TDD se centra en que los desarrolladores escriban pruebas de código fallidas antes de la implementación. BDD se centra en que todo un equipo acuerde el comportamiento utilizando ejemplos en lenguaje sencillo.

¿Puedes usar TDD y BDD juntos?

Sí, y muchos equipos lo hacen. Los escenarios BDD definen características desde el exterior y TDD controla las unidades de código más pequeñas debajo de ellos.

¿BDD es mejor que TDD?

Ninguno de los dos es mejor en general, ya que resuelven problemas diferentes. BDD ayuda con la comprensión compartida y TDD ayuda con el diseño de código y la retroalimentación rápida.

¿Qué es el pepinillo?

Gherkin es un formato estructurado de lenguaje sencillo para escribir escenarios, utilizando palabras clave como Dado, Cuándo y Entonces. Herramientas como Cucumber pueden ejecutarlo.

¿TDD ralentiza el desarrollo?

Puede parecer más lento al principio, especialmente mientras aprende. Los equipos suelen recuperar tiempo mediante menos errores y cambios más seguros, aunque el efecto varía según el proyecto.

sigue aprendiendo

Trabajar con Stack Quora

¿Necesitas ayuda con pruebas, WordPress o SEO?

Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.

Sigue leyendo

Más guías sobre testing, IA y desarrollo moderno

¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.

Inteligencia artificial

Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas

Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…

Leer artículo →
DevOps

Explicación de las variables de entorno: archivos .env, secretos y configuración bien hechos

Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…

Leer artículo →
Desarrollo de software

Explicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429

La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …

Leer artículo →
Automatización de pruebas

Burlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan

Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…

Leer artículo →
Pruebas de software

Explicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%

Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…

Leer artículo →
Bases de datos y SQL

DELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno

DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…

Leer artículo →
Bases de datos y SQL

Vistas SQL explicadas: cree, use y evite los errores, con ejemplos

Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…

Leer artículo →
Desarrollo de software

Interfaz TypeScript versus tipo: diferencias reales, probadas con el compilador

Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…

Leer artículo →
Desarrollo de software

Python *args y **kwargs explicados: funciones flexibles con ejemplos claros

Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…

Leer artículo →
Desarrollo de software

Funciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas

Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…

Leer artículo →
Inteligencia artificial

¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar

¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…

Leer artículo →
DevOps

Monitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos

Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…

Leer artículo →
DevOps

Docker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta

Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…

Leer artículo →
Automatización de pruebas

TDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …

Leer artículo →
Desarrollo de software

Git merge vs rebase: diferencias, ejemplos y cuándo usar cada uno

Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.

Leer artículo →
Desarrollo de software

List comprehension en Python: sintaxis, ejemplos y cuándo evitarla

List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.

Leer artículo →