Escribir la prueba antes que el código
El desarrollo guiado por pruebas, en inglés test-driven development o TDD, consiste en escribir primero una prueba que falla. Después escribes el código que la hace pasar. Te obliga a decidir qué debe hacer la función antes de escribirla.
Una tienda quiere una etiqueta de existencias: agotado, quedan pocas o disponible. Empiezas por tres pruebas pequeñas, no por el código.
Al final de esta lección
Nota
Puedo escribir una prueba que falla, hacerla pasar y ordenar el código.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Rojo | una prueba nueva que falla |
| Verde | todas las pruebas pasan |
| Refactorizar | ordenar el código sin cambiar lo que hace |
| TDD | escribir la prueba antes que el código |
| Paso pequeño | añadir una sola prueba cada vez |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
El ciclo es rojo, verde y refactorizar
Primero escribes una prueba y la ejecutas. Debe fallar: es rojo. Si pasa sin código, la prueba no sirve.
Después escribes lo mínimo para que pase: es verde. Al final ordenas el código sin cambiar lo que hace: refactorizar. Luego empiezas otra vez con una prueba nueva.
Entra en la carpeta de trabajo
mkdir -p ~/pruebas && cd ~/pruebas && rm -f stock.py test_stock.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Rojo: escribe la primera prueba
printf 'import unittest\nfrom stock import etiqueta\n\nclass PruebaStock(unittest.TestCase):\n def test_agotado(self):\n self.assertEqual(etiqueta(0), "Agotado")\n' > test_stock.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecútala: aún no existe stock.py
python3 -m unittest test_stock 2>&1 | grep -E "^(OK|FAILED)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Verde: lo mínimo que la hace pasar
printf 'def etiqueta(unidades):\n return "Agotado"\n' > stock.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta otra vez
python3 -m unittest test_stock 2>&1 | grep -E "^(OK|FAILED)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lo mínimo puede parecer una trampa
Devolver siempre "Agotado" parece absurdo, pero pasa la prueba. Y dice algo importante: una prueba sola no basta para describir la función.
La siguiente prueba rompe la trampa. Cada prueba nueva obliga a que el código sea un poco más general.
Rojo otra vez: añade la segunda prueba
printf '\n def test_pocas(self):\n self.assertEqual(etiqueta(3), "Quedan pocas")\n' >> test_stock.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta: ahora falla una prueba
python3 -m unittest test_stock 2>&1 | grep -E "^(OK|FAILED)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Verde: amplía la función
printf 'def etiqueta(unidades):\n if unidades == 0:\n return "Agotado"\n return "Quedan pocas"\n' > stock.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta: vuelve el verde
python3 -m unittest test_stock 2>&1 | grep -E "^(OK|FAILED)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente escribe el código entero y añade las pruebas al final, porque «ya sabe lo que hace». Entonces las pruebas copian el código y no lo cuestionan. Escribe la prueba primero y verás en rojo lo que faltaba pensar.
La función con sus pruebas en verde
# Rojo: la prueba existe y falla. Verde: lo mínimo para pasar.
def etiqueta(unidades):
if unidades == 0:
return "Agotado"
if unidades <= 5:
return "Quedan pocas"
return "Disponible"
assert etiqueta(0) == "Agotado"
assert etiqueta(3) == "Quedan pocas"
assert etiqueta(5) == "Quedan pocas"
assert etiqueta(6) == "Disponible"
print("Todo en verde")
# Añade la prueba assert etiqueta(1) == "Quedan pocas".