Cómo usar pytest parametrize para tests con múltiples datos

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.

Scroll al inicio