En TDD, el nombre de una prueba no es un detalle menor. Una prueba debe decir qué comportamiento espera del sistema. Si el nombre es claro, la prueba funciona también como documentación ejecutable.
En este tema practicaremos cómo pasar de nombres genéricos a nombres que expliquen contexto, acción y resultado esperado.
Cuando una prueba falla, pytest muestra el nombre de la prueba. Si el nombre es vago, el fallo aporta poca información. Si el nombre describe comportamiento, el fallo se entiende mucho más rápido.
Un buen nombre ayuda a responder tres preguntas:
Supongamos que tenemos una función para aplicar descuentos. Una prueba con este nombre no comunica demasiado:
Archivo de ejemplo: tests/test_descuentos.py
def test_descuento():
assert aplicar_descuento(100, 10) == 90
Si falla, sabremos que algo relacionado con descuentos no funciona, pero no sabremos qué regla concreta se rompió.
Podemos escribir un nombre más específico:
Archivo a modificar: tests/test_descuentos.py
def test_aplicar_descuento_del_diez_por_ciento():
assert aplicar_descuento(100, 10) == 90
Ahora el nombre comunica mejor qué se espera: aplicar un descuento del 10 por ciento.
Cuando la prueba expresa una regla de negocio, el nombre puede reflejar esa regla:
def test_precio_final_disminuye_segun_porcentaje_de_descuento():
assert aplicar_descuento(100, 10) == 90
Este nombre es más general. Sirve cuando el ejemplo representa una regla, no solo un caso aislado.
Este nombre habla demasiado de cómo podría estar programado el código:
def test_aplicar_descuento_usa_multiplicacion_y_resta():
assert aplicar_descuento(100, 10) == 90
La prueba debería describir comportamiento, no obligar a usar una implementación determinada. Si mañana cambiamos la fórmula interna sin cambiar el resultado, la prueba no debería volverse confusa.
Una convención simple es usar nombres con esta idea:
Por ejemplo:
def test_password_es_invalido_si_tiene_menos_de_ocho_caracteres():
assert es_password_valido("abc") is False
No es una regla obligatoria, pero ayuda a construir nombres expresivos.
En Python es válido usar nombres de funciones en castellano sin acentos. Para pruebas de un curso en español, esto puede mejorar la comprensión del alumno.
def test_envio_es_gratis_si_total_es_cien_o_mas():
assert calcular_envio(100) == 0
Conviene evitar acentos en identificadores Python para mantener compatibilidad y facilitar escritura en distintos teclados.
Un nombre largo no siempre es mejor. Este nombre es preciso, pero pesado:
def test_la_funcion_calcular_envio_devuelve_cero_cuando_el_total_de_la_compra_es_mayor_o_igual_a_cien_pesos():
assert calcular_envio(100) == 0
Podemos reducirlo sin perder la idea principal:
def test_envio_es_gratis_si_total_es_cien_o_mas():
assert calcular_envio(100) == 0
El extremo opuesto también es problemático:
def test_1():
assert calcular_envio(100) == 0
Este nombre no aporta información. Si falla, obliga a abrir el archivo y leer la prueba completa.
Cuando usamos parametrización, un solo nombre cubre varios ejemplos. Por eso debe describir la regla general:
import pytest
@pytest.mark.parametrize(
"total, esperado",
[
(50, 10),
(99, 10),
(100, 0),
],
)
def test_calcular_envio_devuelve_costo_segun_total_de_compra(total, esperado):
assert calcular_envio(total) == esperado
El nombre no menciona un caso específico, sino la regla que todos los casos verifican.
Podemos mejorar el reporte de pytest usando id en cada caso:
import pytest
@pytest.mark.parametrize(
"total, esperado",
[
pytest.param(50, 10, id="compra-menor-a-cien"),
pytest.param(99, 10, id="limite-inferior"),
pytest.param(100, 0, id="envio-gratis"),
],
)
def test_calcular_envio_devuelve_costo_segun_total_de_compra(total, esperado):
assert calcular_envio(total) == esperado
Si un caso falla, el identificador ayuda a ubicar rápidamente qué ejemplo falló.
El archivo también comunica intención. Un archivo llamado test_envio.py agrupa pruebas de envío. Dentro de ese archivo, cada función debe precisar un comportamiento.
tests/
`-- test_envio.py
Evita archivos demasiado genéricos como test_utils.py si terminan mezclando reglas de negocio sin relación clara.
En TDD, si cuesta nombrar una prueba, puede ser señal de que el comportamiento no está claro. Antes de escribir código, conviene aclarar la regla.
Por ejemplo, este nombre revela una ambigüedad:
def test_descuento_es_correcto():
assert aplicar_descuento(100, 10) == 90
¿Correcto según qué regla? ¿Descuento porcentual? ¿Descuento fijo? ¿Cupón? El nombre nos obliga a pensar mejor.
Cambiar el nombre de una prueba es una refactorización. No cambia el comportamiento verificado, pero mejora la comunicación.
Después de renombrar, ejecutamos:
python -m pytest
Si todo sigue en verde, el cambio fue seguro.
Comparación entre nombres poco útiles y nombres más expresivos:
test_descuento: demasiado genérico.test_aplicar_descuento_del_diez_por_ciento: describe un caso concreto.test_precio_final_disminuye_segun_porcentaje_de_descuento: describe una regla.test_1: no comunica comportamiento.test_envio_es_gratis_si_total_es_cien_o_mas: comunica condición y resultado.test_1, test_2 no explican nada.Mejora los nombres de estas pruebas:
def test_envio():
assert calcular_envio(100) == 0
def test_password():
assert es_password_valido("abc") is False
def test_puntos():
assert calcular_puntos(95) == 9
Una posible mejora sería:
def test_envio_es_gratis_si_total_es_cien_o_mas():
assert calcular_envio(100) == 0
def test_password_es_invalido_si_tiene_menos_de_ocho_caracteres():
assert es_password_valido("abc") is False
def test_puntos_ignoran_pesos_que_no_completan_decena():
assert calcular_puntos(95) == 9
Toma tres pruebas de temas anteriores y renómbralas para que el nombre explique mejor el comportamiento. Después ejecuta:
python -m pytest
El objetivo es que todos los tests sigan pasando y que el reporte de pytest sea más comprensible.
Antes de continuar, verifica lo siguiente:
python -m pytest después de renombrar.En este tema vimos que el nombre de una prueba es parte de su valor. Una prueba bien nombrada ayuda a entender el requisito, diagnosticar fallos y usar la suite como documentación ejecutable.
En el próximo tema ordenaremos el cuerpo de las pruebas con el patrón Arrange, Act, Assert para que, además del nombre, la estructura interna también sea clara.