En pytest, la mayoría de las comprobaciones se escriben con la palabra clave assert. A diferencia de unittest, no necesitamos llamar métodos como assertEqual o assertTrue.
En este tema veremos cómo usar assert para comparar distintos valores y cómo leer los mensajes que muestra pytest cuando una prueba falla.
Crea un proyecto nuevo:
mkdir pytest-assert-demo
cd pytest-assert-demo
Si no tienes pytest instalado en el entorno activo, instálalo con:
python -m pip install pytest
Crea un archivo llamado analisis.py:
def calcular_promedio(valores):
if not valores:
return 0
return sum(valores) / len(valores)
def normalizar_etiqueta(texto):
return texto.strip().lower().replace(" ", "-")
def obtener_aprobados(estudiantes):
return [estudiante for estudiante in estudiantes if estudiante["nota"] >= 6]
def resumir_estudiante(nombre, nota):
return {
"nombre": nombre.strip().title(),
"nota": nota,
"aprobado": nota >= 6,
}
def validar_nota(nota):
if nota < 0 or nota > 10:
raise ValueError("La nota debe estar entre 0 y 10")
return nota
Usaremos estas funciones para probar números, cadenas, listas, diccionarios, booleanos y excepciones.
Crea test_analisis.py:
from analisis import calcular_promedio
def test_calcular_promedio():
resultado = calcular_promedio([8, 6, 10])
assert resultado == 8
Esta es una aserción básica: si resultado vale 8, la prueba pasa.
Ejecuta:
python -m pytest
La salida esperada será similar a:
collected 1 item
test_analisis.py . [100%]
1 passed in 0.02s
Para números enteros o resultados exactos usamos ==:
def test_promedio_de_lista_vacia_es_cero():
resultado = calcular_promedio([])
assert resultado == 0
Si la función devolviera otro valor, pytest mostraría el valor obtenido y la expresión que falló.
Importa normalizar_etiqueta y agrega esta prueba:
from analisis import normalizar_etiqueta
def test_normalizar_etiqueta():
resultado = normalizar_etiqueta(" Curso Python ")
assert resultado == "curso-python"
Cuando fallan cadenas largas, pytest ayuda a ver diferencias entre el texto esperado y el obtenido.
Para comprobar un booleano exacto, usa is True o is False:
from analisis import resumir_estudiante
def test_estudiante_con_nota_6_esta_aprobado():
estudiante = resumir_estudiante("Ana", 6)
assert estudiante["aprobado"] is True
def test_estudiante_con_nota_5_no_esta_aprobado():
estudiante = resumir_estudiante("Luis", 5)
assert estudiante["aprobado"] is False
Esto deja claro que esperamos exactamente un valor booleano.
Las listas se comparan por contenido y por orden:
from analisis import obtener_aprobados
def test_obtener_aprobados():
estudiantes = [
{"nombre": "Ana", "nota": 8},
{"nombre": "Luis", "nota": 5},
{"nombre": "Marta", "nota": 7},
]
resultado = obtener_aprobados(estudiantes)
assert resultado == [
{"nombre": "Ana", "nota": 8},
{"nombre": "Marta", "nota": 7},
]
Si falta un elemento, sobra otro o cambia el orden, la aserción falla.
Los diccionarios pueden compararse completos:
def test_resumir_estudiante():
resultado = resumir_estudiante(" ana ", 9)
assert resultado == {
"nombre": "Ana",
"nota": 9,
"aprobado": True,
}
Cuando un diccionario falla, pytest suele mostrar qué claves o valores son diferentes.
Podemos usar in dentro de un assert:
def test_nombre_normalizado_contiene_guion():
resultado = normalizar_etiqueta("Curso Python")
assert "-" in resultado
También sirve para listas, tuplas, conjuntos y claves de diccionarios.
Para errores esperados seguimos usando pytest.raises:
import pytest
from analisis import validar_nota
def test_nota_mayor_a_10_lanza_error():
with pytest.raises(ValueError):
validar_nota(11)
Si no se lanza la excepción, la prueba falla.
Para revisar el mensaje:
def test_nota_invalida_muestra_mensaje_claro():
with pytest.raises(ValueError) as error:
validar_nota(-1)
assert str(error.value) == "La nota debe estar entre 0 y 10"
Usa esta técnica cuando el texto del error sea relevante para el proyecto.
Cambia temporalmente una expectativa para que sea incorrecta:
def test_calcular_promedio():
resultado = calcular_promedio([8, 6, 10])
assert resultado == 7
Al ejecutar python -m pytest, verás una salida similar:
E assert 8.0 == 7
La línea indica que la expresión falló porque el valor obtenido fue 8.0 y el esperado era 7. Después de observar la falla, vuelve a dejar el valor correcto.
Cuando una prueba falla, pytest muestra información en varias partes:
| Parte del reporte | Qué indica |
|---|---|
| Nombre de la prueba | Qué función de prueba falló. |
| Línea del archivo | En qué línea ocurrió la aserción fallida. |
| Expresión del assert | Qué comparación no se cumplió. |
| Valores obtenidos | Qué datos reales participaron en la comparación. |
Python permite agregar un mensaje al assert:
def test_promedio_esperado_con_mensaje():
resultado = calcular_promedio([8, 6, 10])
assert resultado == 8, "El promedio debe calcularse sumando valores y dividiendo por la cantidad"
No hace falta agregar mensajes a todas las pruebas. Úsalos cuando expliquen una regla de negocio o una intención que no sea obvia.
El archivo test_analisis.py puede quedar así:
import pytest
from analisis import (
calcular_promedio,
normalizar_etiqueta,
obtener_aprobados,
resumir_estudiante,
validar_nota,
)
def test_calcular_promedio():
resultado = calcular_promedio([8, 6, 10])
assert resultado == 8
def test_promedio_de_lista_vacia_es_cero():
resultado = calcular_promedio([])
assert resultado == 0
def test_normalizar_etiqueta():
resultado = normalizar_etiqueta(" Curso Python ")
assert resultado == "curso-python"
def test_estudiante_con_nota_6_esta_aprobado():
estudiante = resumir_estudiante("Ana", 6)
assert estudiante["aprobado"] is True
def test_estudiante_con_nota_5_no_esta_aprobado():
estudiante = resumir_estudiante("Luis", 5)
assert estudiante["aprobado"] is False
def test_obtener_aprobados():
estudiantes = [
{"nombre": "Ana", "nota": 8},
{"nombre": "Luis", "nota": 5},
{"nombre": "Marta", "nota": 7},
]
resultado = obtener_aprobados(estudiantes)
assert resultado == [
{"nombre": "Ana", "nota": 8},
{"nombre": "Marta", "nota": 7},
]
def test_resumir_estudiante():
resultado = resumir_estudiante(" ana ", 9)
assert resultado == {
"nombre": "Ana",
"nota": 9,
"aprobado": True,
}
def test_nombre_normalizado_contiene_guion():
resultado = normalizar_etiqueta("Curso Python")
assert "-" in resultado
def test_nota_mayor_a_10_lanza_error():
with pytest.raises(ValueError):
validar_nota(11)
def test_nota_invalida_muestra_mensaje_claro():
with pytest.raises(ValueError) as error:
validar_nota(-1)
assert str(error.value) == "La nota debe estar entre 0 y 10"
Ejecuta:
python -m pytest
La salida esperada será similar a:
collected 10 items
test_analisis.py .......... [100%]
10 passed in 0.03s
Para ver nombres de pruebas y un reporte más explícito:
python -m pytest -v
Cuando estás leyendo fallas, la salida detallada ayuda a ubicar el caso exacto más rápido.
assert resultado cuando querías comparar un valor exacto: puede pasar con valores verdaderos pero incorrectos.mkdir pytest-assert-demo
cd pytest-assert-demo
python -m pip install pytest
python -m pytest
python -m pytest -v
python -m pytest test_analisis.py
pytest usa assert para expresar comprobaciones.pytest.raises permite verificar excepciones esperadas.En este tema profundizamos en las aserciones con assert y en la lectura de fallas de pytest. Vimos cómo comparar distintos tipos de datos y cómo interpretar el reporte cuando una expectativa no se cumple.
En el próximo tema aprenderemos a ejecutar una prueba, un archivo, una carpeta o toda la suite para trabajar con mayor precisión.