Definiciones de Pasos
Las definiciones de pasos son funciones de Python que ejecutan pasos de Gherkin. Los buenos pasos son envolturas reutilizables y delgadas sobre el código de la aplicación, y comparten estado a través de fixtures u objetos de contexto.
Receta
from pytest_bdd import given, when, then, parsers
@given(parsers.parse('un usuario con email "{email}"'))
def user_with_email(email, user_factory):
return user_factory(email=email)
@when("inician sesión")
def login(user_with_email, auth_client):
auth_client.login(user_with_email)
@then(parsers.parse('ven "{message}"'))
def see_message(message, page):
assert message in page.contentCuándo recurrir a esto:
- Mapeo de texto Gherkin a ejecución de Python
- Creación de una biblioteca de pasos reutilizables
- Análisis de parámetros a partir de texto de paso en lenguaje natural
Ejemplo de Trabajo
# features/steps/common.py
from pytest_bdd import given, when, then, parsers
import httpx
class APIContext:
def __init__(self):
self.client = None
self.response = None
self.token = None
@given("un cliente API autenticado")
def auth_client(context: APIContext, test_token):
context.client = httpx.Client(
base_url="http://testserver",
headers={"Authorization": f"Bearer {test_token}"},
)
context.token = test_token
@when(parsers.parse('envío una solicitud {method} a "{path}"'))
def send_request(context: APIContext, method, path):
context.response = context.client.request(method, path)
@then(parsers.parse("el estado de la respuesta es {code:d}"))
def check_status(context: APIContext, code):
assert context.response.status_code == code
@then(parsers.cfparse("la respuesta contiene {count:d} elementos"))
def check_count(context: APIContext, count):
data = context.response.json()
assert len(data) == countLo que esto demuestra:
- El objeto de contexto mantiene el estado por escenario
parsers.parseyparsers.cfparseextraen parámetros tipados- Pasos reutilizables compartidos entre archivos de características
- Los pasos delegan al código de la aplicación, no lo reimplementan
Inmersión Profunda
Coincidencia de Pasos
- Coincidencia exacta de texto primero
parsers.parsepara{name},{name:d},{name:f},{name:w}(palabra)- Gana la coincidencia más larga cuando varios pasos podrían aplicarse
Capas
Archivo de características (qué)
-> Definición de paso (pegamento delgado)
-> Servicio de aplicación (cómo)
-> Lógica de dominio
Errores Comunes
- Definiciones de pasos "gordas": lógica de negocio en los pasos. Solución: llamar a funciones de servicio; los pasos son pegamento de una sola línea.
- Texto de paso ambiguo: múltiples coincidencias. Solución: hacer los pasos más específicos o usar anclas de expresiones regulares.
- Contexto mutable compartido: el escenario A afecta al escenario B. Solución: contexto nuevo por escenario (ámbito de fixture=función).
- Parámetros fuertemente tipados como cadenas:
"100"vs100. Solución: usar analizadores tipados{amount:f}o{amount:d}. - Definiciones de pasos duplicadas: error de registro. Solución: una definición por texto de paso; compartir a través de importaciones.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Pasos genéricos | Dominios altamente parametrizados | Los pasos se vuelven ilegibles |
| Patrón de Objeto de Página | Pruebas de UI | Proyectos solo de API |
| pytest directo | No se necesita Gherkin | Se requiere colaboración de las partes interesadas |
Preguntas Frecuentes
¿Cómo paso datos entre pasos?
Objeto de contexto, fixtures de pytest o el atributo context de behave.
¿Pueden los pasos llamar a otros pasos?
Evitar. Extraer la lógica compartida en funciones auxiliares en su lugar.
¿Cómo manejo tablas en los pasos?
pytest-bdd: target_fixture y parámetro datatable. behave: context.table.
¿Qué es parsers.cfparse?
Analiza formato con más especificadores de tipo que el análisis básico. Parte de pytest-bdd.
¿Cómo reutilizo pasos entre proyectos?
Publicar un paquete steps/ compartido instalado con pip como dependencia de desarrollo.
¿Cómo pruebo las definiciones de pasos?
Llamar a la función de Python directamente en pruebas unitarias con contexto simulado.
¿Pasos Given como fixtures?
pytest-bdd soporta target_fixture=True en @given para inyectar como fixture.
¿Cómo manejo pasos asíncronos?
pytest-bdd con pytest-asyncio: funciones de paso async def.
Error de paso no encontrado?
El texto Gherkin debe coincidir exactamente. Verifique los espacios finales y el estilo de las comillas.
¿Cuántos pasos compartidos?
10-20 pasos comunes (autenticación, cliente API, aserciones). Los pasos específicos de la característica permanecen locales.
Relacionado
- Sintaxis Gherkin - autoría de texto de paso
- Configuración de behave / pytest-bdd - cableado del proyecto
- Gherkin a Código - flujo de implementación
- Fixtures - patrones de fixtures de pytest
Versiones de la pila: Esta página fue escrita para Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.