Hay una situación que se repite constantemente cuando escribes tests: tienes la misma lógica de prueba pero con diferentes datos de entrada. Sin parametrize acabas duplicando el mismo test una y otra vez cambiando solo los valores. Con parametrize lo escribes una vez y pytest lo ejecuta automáticamente con todos los datos que le indiques.
Qué es pytest parametrize
pytest.mark.parametrize es un decorator de pytest que permite ejecutar el mismo test múltiples veces con diferentes conjuntos de datos. Cada combinación de datos se ejecuta como un test independiente con su propio resultado en el reporte.
El problema que resuelve
Sin parametrize, probar un formulario de login con tres usuarios distintos requiere tres tests separados con código casi idéntico:
python
# Sin parametrize — código duplicado
def test_login_usuario_valido(page):
page.fill("#email", "usuario1@test.com")
page.fill("#password", "password123")
page.click("#btn-login")
assert "dashboard" in page.url
def test_login_admin(page):
page.fill("#email", "admin@test.com")
page.fill("#password", "admin456")
page.click("#btn-login")
assert "dashboard" in page.url
def test_login_manager(page):
page.fill("#email", "manager@test.com")
page.fill("#password", "manager789")
page.click("#btn-login")
assert "dashboard" in page.url
Con parametrize, un solo test hace el trabajo de los tres:
python
import pytest
from playwright.sync_api import Page
@pytest.mark.parametrize("email,password", [
("usuario1@test.com", "password123"),
("admin@test.com", "admin456"),
("manager@test.com", "manager789"),
])
def test_login_multiples_usuarios(page: Page, email, password):
page.goto("https://miweb.com/login")
page.fill("#email", email)
page.fill("#password", password)
page.click("#btn-login")
assert "dashboard" in page.url
pytest ejecuta este test tres veces — una por cada tupla de datos — y los muestra como tests independientes en el reporte.
Parametrize con un solo parámetro
Si solo necesitas un parámetro, la sintaxis es más simple:
python
@pytest.mark.parametrize("url", [
"https://miweb.com",
"https://miweb.com/productos",
"https://miweb.com/contacto",
"https://miweb.com/sobre-nosotros",
])
def test_paginas_cargan_correctamente(page: Page, url):
page.goto(url)
assert page.title() != ""
assert page.locator("nav").is_visible()
assert page.locator("footer").is_visible()
Con este test verificas que cuatro páginas diferentes tienen título, navegación y footer con un solo bloque de código.
Parametrize con resultado esperado
Una de las combinaciones más útiles es parametrizar tanto los datos de entrada como el resultado esperado:
python
@pytest.mark.parametrize("email,password,resultado_esperado", [
("usuario@test.com", "password123", "dashboard"), # Login correcto
("usuario@test.com", "wrongpass", "login"), # Contraseña incorrecta
("noexiste@test.com", "password123", "login"), # Usuario inexistente
("", "", "login"), # Campos vacíos
("notanemail", "password123", "login"), # Email inválido
])
def test_login_casos(page: Page, email, password, resultado_esperado):
page.goto("https://miweb.com/login")
page.fill("#email", email)
page.fill("#password", password)
page.click("#btn-login")
assert resultado_esperado in page.url
Este test cubre cinco escenarios distintos — válido e inválidos — con un solo bloque de código.
Añadir IDs descriptivos a los parámetros
Por defecto pytest genera IDs automáticos para cada combinación de parámetros — test_login_casos[email0-password0-dashboard]. Puedes hacerlos más legibles con el parámetro ids:
python
@pytest.mark.parametrize("email,password,esperado", [
("usuario@test.com", "password123", "dashboard"),
("usuario@test.com", "wrongpass", "login"),
("", "", "login"),
], ids=[
"login_correcto",
"password_incorrecta",
"campos_vacios"
])
def test_login_con_ids(page: Page, email, password, esperado):
page.goto("https://miweb.com/login")
page.fill("#email", email)
page.fill("#password", password)
page.click("#btn-login")
assert esperado in page.url
Ahora en el reporte los tests se muestran como test_login_con_ids[login_correcto], test_login_con_ids[password_incorrecta] y test_login_con_ids[campos_vacios] — mucho más claro.
Parametrize con fixtures
Puedes combinar parametrize con fixtures para crear tests muy potentes. Por ejemplo, ejecutar los mismos tests parametrizados en múltiples entornos:
python
@pytest.fixture(params=["staging", "production"])
def base_url(request):
urls = {
"staging": "https://staging.miweb.com",
"production": "https://miweb.com"
}
return urls[request.param]
@pytest.mark.parametrize("pagina", ["/", "/productos", "/contacto"])
def test_paginas_en_todos_entornos(page: Page, base_url, pagina):
page.goto(f"{base_url}{pagina}")
assert page.title() != ""
Este test se ejecuta 6 veces — 3 páginas × 2 entornos — verificando que todas las páginas funcionan tanto en staging como en producción.
Cargar datos de prueba desde un archivo
Cuando tienes muchos conjuntos de datos, lo más limpio es cargarlos desde un archivo externo en lugar de tenerlos hardcodeados en el test:
python
import json
import pytest
from playwright.sync_api import Page
def cargar_usuarios():
with open("tests/data/usuarios.json") as f:
return [(u["email"], u["password"]) for u in json.load(f)]
@pytest.mark.parametrize("email,password", cargar_usuarios())
def test_login_desde_archivo(page: Page, email, password):
page.goto("https://miweb.com/login")
page.fill("#email", email)
page.fill("#password", password)
page.click("#btn-login")
assert "dashboard" in page.url
El archivo usuarios.json contendría algo así:
json
[
{"email": "usuario1@test.com", "password": "password123"},
{"email": "usuario2@test.com", "password": "pass456"},
{"email": "admin@test.com", "password": "admin789"}
]
Esto es especialmente útil cuando los datos de prueba son muchos o cuando cambian frecuentemente — solo hay que actualizar el JSON sin tocar el código del test.
Cuándo usar parametrize y cuándo no
Usa parametrize cuando tienes la misma lógica de prueba con diferentes datos de entrada, cuando quieres probar casos límite y casos de error con el mismo test, o cuando necesitas verificar el mismo comportamiento en múltiples entornos o configuraciones.
No abuses de parametrize cuando los datos son tan diferentes que realmente representan comportamientos distintos — en ese caso es mejor tener tests separados con nombres descriptivos.
Si quieres profundizar en pytest puedes leer cómo usar fixtures en pytest o cómo generar reportes HTML con pytest.
Y si necesitas ayuda para diseñar una estrategia de tests eficiente puedes ver mis servicios en fatimaqa.com.
