El nombre de una prueba unitaria es más importante de lo que parece. Una prueba no solo ejecuta una verificación: también comunica una intención a quienes leen y mantienen el código.
Cuando una prueba falla, muchas veces lo primero que vemos es su nombre. Si el nombre es claro, ya tenemos una pista sobre el comportamiento que se rompió. Si el nombre es genérico, debemos abrir la prueba y leer todo el cuerpo para entender qué ocurrió.
En este tema veremos cómo elegir nombres útiles, qué formatos se usan habitualmente y qué errores conviene evitar.
Un buen nombre de prueba debería comunicar tres ideas:
Por ejemplo, el nombre test_edad_18_puede_registrarse comunica una situación concreta y un resultado esperado. En cambio, test_registro es demasiado general.
Supongamos una función que decide si una persona puede registrarse según su edad.
def puede_registrarse(edad):
return edad >= 18
def test_edad_17_no_puede_registrarse():
assert puede_registrarse(17) == False
def test_edad_18_puede_registrarse():
assert puede_registrarse(18) == True
Estos nombres son útiles porque muestran el caso probado y el resultado esperado. Si falla test_edad_18_puede_registrarse, sabemos que el problema está en el límite de mayoría de edad o en la regla asociada.
Los nombres genéricos son uno de los errores más frecuentes al comenzar.
def test_usuario():
...
def test_calculo():
...
def test_funciona():
...
Estos nombres no indican qué comportamiento se verifica. Cuando fallan, no aportan información. Además, con el tiempo aparecen muchas pruebas con nombres parecidos y la suite se vuelve difícil de navegar.
El extremo opuesto es usar nombres que describen detalles internos en lugar del comportamiento esperado.
def test_if_linea_8_retorna_true():
...
def test_variable_auxiliar_queda_en_15():
...
Estos nombres acoplan la prueba a la implementación. Si refactorizamos el código sin cambiar el comportamiento, los nombres dejan de tener sentido. Conviene nombrar pruebas desde el punto de vista del comportamiento observable.
Un formato práctico es:
Ejemplos:
test_calcular_descuento_cliente_vip_devuelve_15_por_cientotest_validar_password_con_menos_de_8_caracteres_fallatest_carrito_vacio_tiene_total_cerotest_transferencia_mayor_al_saldo_es_rechazadaNo todos los equipos usan exactamente este formato, pero la idea central se mantiene: el nombre debe explicar el caso.
Otra forma común toma inspiración de la estructura "dado, cuando, entonces":
Ejemplo:
def test_dado_carrito_con_items_cuando_calcula_total_entonces_devuelve_suma():
carrito = Carrito()
carrito.agregar_item(100)
carrito.agregar_item(50)
total = carrito.calcular_total()
assert total == 150
Este formato puede ser muy expresivo, aunque a veces produce nombres largos. Conviene usarlo cuando la claridad extra justifica la longitud.
Algunos equipos usan nombres que expresan el comportamiento esperado con la palabra "debería".
def test_deberia_rechazar_transferencia_si_no_hay_saldo_suficiente():
cuenta = Cuenta(saldo=100)
resultado = cuenta.puede_transferir(150)
assert resultado == False
La ventaja es que el nombre se lee como una especificación. La desventaja es que, si se abusa, muchos nombres empiezan igual y la parte importante queda al final.
No existe un único estilo obligatorio para nombrar pruebas. Lo importante es que el equipo use una convención consistente.
Un proyecto con nombres mezclados puede ser difícil de recorrer:
test_usuarioshouldValidateUserAgetest_dado_usuario_menor_entonces_errorpruebaEdadIncorrectaLa consistencia facilita buscar pruebas, entender reportes y mantener la suite.
Los casos límite deben quedar claramente identificados en el nombre. Esto ayuda a entender por qué se eligieron ciertos valores.
def password_tiene_longitud_valida(password):
return len(password) >= 8
def test_password_de_7_caracteres_no_es_valido():
assert password_tiene_longitud_valida("abcdefg") == False
def test_password_de_8_caracteres_es_valido():
assert password_tiene_longitud_valida("abcdefgh") == True
Los nombres explican que 7 y 8 no son valores casuales: están alrededor del límite de la regla.
Cuando el comportamiento esperado es un error controlado, el nombre debe decirlo con claridad.
def dividir(a, b):
if b == 0:
raise ValueError("No se puede dividir por cero")
return a / b
def test_dividir_por_cero_lanza_value_error():
try:
dividir(10, 0)
assert False
except ValueError:
assert True
El nombre indica la condición y el error esperado. Esto es más claro que un nombre como test_dividir_error.
Cuando la prueba verifica un cambio de estado, el nombre debe indicar el estado inicial, la acción o el resultado final.
def test_depositar_incrementa_el_saldo_en_el_importe_indicado():
cuenta = Cuenta(100)
cuenta.depositar(50)
assert cuenta.saldo == 150
Este nombre comunica que la prueba no solo verifica que el método se ejecute, sino que el saldo aumenta correctamente.
En reglas de negocio conviene usar vocabulario del dominio. Eso ayuda a que la prueba sea entendible incluso para personas que conocen el negocio pero no todos los detalles internos del código.
def test_cliente_vip_recibe_descuento_del_15_por_ciento():
descuento = calcular_descuento(tipo_cliente="vip", monto=1000)
assert descuento == 150
El nombre usa términos como cliente_vip y descuento, que pertenecen al dominio. Esto es mejor que nombrar la prueba según variables internas.
En pruebas parametrizadas, una misma prueba se ejecuta con varios datos. El nombre general debe describir la regla, y los parámetros deben ayudar a identificar cada caso.
def test_edades_mayores_o_iguales_a_18_pueden_registrarse():
edades_validas = [18, 19, 30]
for edad in edades_validas:
assert puede_registrarse(edad) == True
Más adelante veremos pruebas parametrizadas con herramientas específicas. Por ahora, la idea importante es que el nombre explique la regla común a todos los datos.
El nombre de una prueba debe coincidir con lo que realmente verifica. Si el nombre dice que valida todo el registro de usuario, pero la prueba solo verifica la edad, el nombre es engañoso.
def test_registro_completo_de_usuario():
assert puede_registrarse(18) == True
Un nombre más honesto sería:
def test_usuario_de_18_anios_puede_registrarse():
assert puede_registrarse(18) == True
Una prueba debe prometer exactamente lo que comprueba.
Un nombre largo no es necesariamente malo si aporta claridad. En pruebas unitarias, suele ser aceptable usar nombres más descriptivos que en funciones de producción.
Comparación:
| Nombre | Evaluación |
|---|---|
test_descuento |
Demasiado general. |
test_cliente_vip_recibe_descuento |
Más claro. |
test_cliente_vip_con_compra_de_1000_recibe_descuento_de_150 |
Muy específico, útil si ese caso es importante. |
El objetivo no es escribir el nombre más corto, sino el más útil.
Cuando ejecutamos una suite, las herramientas suelen mostrar el nombre de las pruebas que fallan. Por eso el nombre debe ser informativo incluso fuera del contexto del archivo.
Un reporte que dice test_calculo falló obliga a investigar desde cero. Un reporte que dice test_descuento_cero_no_modifica_precio ya indica qué comportamiento se rompió.
Los buenos nombres reducen tiempo de diagnóstico.
| Nombre débil | Nombre más claro |
|---|---|
test_usuario |
test_usuario_menor_de_edad_no_puede_registrarse |
test_total |
test_carrito_con_dos_items_calcula_total_correcto |
test_error |
test_dividir_por_cero_lanza_value_error |
test_descuento_ok |
test_cliente_vip_recibe_descuento_del_15_por_ciento |
test_password |
test_password_de_7_caracteres_no_es_valido |
Antes de dejar una prueba, revisa su nombre:
Si el nombre no responde estas preguntas, probablemente puede mejorarse.
Nombrar bien una prueba unitaria es parte del diseño de la prueba. Un nombre claro ayuda a leer la suite, entender reglas, diagnosticar fallas y mantener el proyecto con menos esfuerzo.
Las pruebas son documentación ejecutable, y el nombre es la primera línea de esa documentación. Por eso conviene dedicarle atención.
En el próximo tema estudiaremos las aserciones, que son las comprobaciones que determinan si una prueba pasa o falla.