EARS + Gherkin

Por: Artiko
earsgherkinbddcucumberpuente

EARS + Gherkin

EARS y Gherkin trabajan en capas distintas pero complementarias:

CapaLenguajePregunta que responde
RequisitoEARS¿Qué debe hacer el sistema?
EscenarioGherkin¿Cómo verificamos que lo hace?

Un requisito EARS típico se convierte en uno o varios escenarios Gherkin. EARS es el contrato, Gherkin son los ejemplos ejecutables del contrato.

Mapeo conceptual

flowchart LR
    REQ[Requisito EARS<br/>When/While/Where/If] --> Scenario[Scenario Gherkin<br/>Given/When/Then]
    REQ -.->|disparador| ScenWhen[When del Gherkin]
    REQ -.->|sujeto + respuesta| ScenThen[Then del Gherkin]
    REQ -.->|estado/feature| ScenGiven[Given del Gherkin]

Reglas de derivación:

Ejemplo 1: derivación 1:1

EARS:

REQ-AUTH-001: When the user submits valid credentials to /auth/login, the auth service shall return HTTP 200 with a JWT valid for 24 hours.

Gherkin derivado:

Feature: Login con credenciales válidas

  Scenario: Usuario existente con credenciales correctas obtiene un JWT
    Given un usuario registrado con email "[email protected]" y password "secret123"
    When envío POST /auth/login con email "[email protected]" y password "secret123"
    Then la respuesta tiene status 200
    And el cuerpo contiene un campo "token" con un JWT
    And el JWT expira en 24 horas

Un requisito → un escenario. Trazabilidad directa.

Ejemplo 2: un EARS, múltiples escenarios

EARS:

REQ-AUTH-002: If the credentials are invalid, then the auth service shall return HTTP 401 with body { "error": "invalid_credentials" } indistinguishably between "user not found" and "wrong password".

Gherkin derivado (dos escenarios cubren el mismo REQ):

Feature: Login con credenciales inválidas

  Scenario: Usuario inexistente
    Given que no existe un usuario con email "[email protected]"
    When envío POST /auth/login con email "[email protected]" y password "anything"
    Then la respuesta tiene status 401
    And el cuerpo es { "error": "invalid_credentials" }

  Scenario: Contraseña incorrecta para usuario existente
    Given un usuario registrado con email "[email protected]" y password "secret123"
    When envío POST /auth/login con email "[email protected]" y password "wrong-password"
    Then la respuesta tiene status 401
    And el cuerpo es { "error": "invalid_credentials" }

  Scenario: Las respuestas son indistinguibles entre usuario inexistente y contraseña incorrecta
    Given que no existe un usuario con email "[email protected]"
    And un usuario registrado con email "[email protected]" y password "secret123"
    When envío POST /auth/login con email "[email protected]" y password "anything"
    And capturo la respuesta como R1
    When envío POST /auth/login con email "[email protected]" y password "wrong-password"
    And capturo la respuesta como R2
    Then R1.status es igual a R2.status
    And R1.body es igual a R2.body

El REQ se cubre con 3 escenarios — uno por caso de borde.

Ejemplo 3: Scenario Outline para Where

Los requisitos con Where (optional feature) a menudo dan lugar a Scenario Outlines:

EARS:

REQ-EXPORT-001: Where the user has subscription <plan>, when the user requests an export, the service shall allow files up to <max_size> MB.

Gherkin derivado:

Feature: Tamaño máximo de export según plan

  Scenario Outline: Límite de export por plan
    Given un usuario con subscription "<plan>"
    When solicito export de "<size>" MB
    Then la respuesta tiene status "<expected_status>"

    Examples:
      | plan    | size | expected_status |
      | free    | 10   | 200             |
      | free    | 50   | 413             |
      | pro     | 50   | 200             |
      | pro     | 200  | 413             |
      | premium | 500  | 200             |
      | premium | 2000 | 413             |

Una sola tabla cubre todas las combinaciones del requisito.

Trazabilidad EARS ↔ Gherkin

Agregá el REQ-ID como tag en el feature/scenario:

Feature: Autenticación

  @REQ-AUTH-001
  Scenario: Usuario obtiene JWT con credenciales válidas
    Given ...

  @REQ-AUTH-002
  Scenario: Credenciales inválidas devuelven 401
    Given ...

Esto permite reportes automatizados de cobertura de requisitos — qué REQ tienen al menos un escenario, cuáles no.

EARS para describir el comportamiento del sistema; Gherkin para describir ejemplos

Recordá la diferencia:

Por eso un EARS puede dar lugar a varios Gherkin: el sistema dice “rechazá credenciales inválidas”, los escenarios dicen “acá hay tres formas en las que pueden ser inválidas”.

Anti-patrón: Gherkin sin EARS de soporte

Si los escenarios Gherkin se escriben sin requisitos EARS previos, suelen quedar:

Con EARS de soporte, los Gherkin se escriben como instanciación del requisito.

Anti-patrón: EARS sin Gherkin de verificación

Si los EARS no se traducen a tests automatizados, el contrato se rompe con el tiempo. EARS sin verificación es papel.

Flujo recomendado

flowchart TD
    A[Stakeholder o PO<br/>describe necesidad] --> B[Requisitos en EARS]
    B --> C[Refinamiento: discutir AC]
    C --> D[Escenarios Gherkin<br/>derivados de cada REQ]
    D --> E[Step definitions<br/>en código]
    E --> F[Ejecutar BDD<br/>en CI]
    F -->|todos pasan| G[Feature aceptada]
    F -->|falla| H[Volver a REQ o impl]

Ejemplo completo: feature con trazabilidad

Spec EARS:

# Spec: Carrito de compras

REQ-CART-001: When the user adds a product to the cart, the cart service shall increment the quantity if the product is already in the cart, or insert it with quantity 1 if not.

REQ-CART-002: When the user removes a product from the cart, the cart service shall remove the line item completely regardless of quantity.

REQ-CART-003: While the cart is empty, the checkout button shall be disabled.

REQ-CART-004: If the cart subtotal exceeds $10000, then the cart service shall require manager approval before checkout.

Gherkin derivado:

Feature: Carrito de compras

  @REQ-CART-001
  Scenario: Agregar producto nuevo al carrito
    Given un carrito vacío
    When agrego el producto "P-100" al carrito
    Then el carrito contiene 1 línea
    And la línea de "P-100" tiene quantity 1

  @REQ-CART-001
  Scenario: Agregar producto que ya está en el carrito incrementa quantity
    Given un carrito con la línea (P-100, quantity 2)
    When agrego el producto "P-100" al carrito
    Then el carrito contiene 1 línea
    And la línea de "P-100" tiene quantity 3

  @REQ-CART-002
  Scenario: Remover producto elimina la línea completa
    Given un carrito con la línea (P-100, quantity 5)
    When remuevo el producto "P-100" del carrito
    Then el carrito está vacío

  @REQ-CART-003
  Scenario: Botón checkout deshabilitado con carrito vacío
    Given un carrito vacío
    When abro la vista del carrito
    Then el botón "Checkout" está deshabilitado

  @REQ-CART-004
  Scenario: Carrito sobre el límite requiere aprobación
    Given un carrito con subtotal $15000
    When inicio el checkout
    Then la respuesta indica "requires_manager_approval: true"
    And no se procesa el pago hasta recibir aprobación

Cada escenario traza a un REQ vía tag. Revisión y reportes triviales.

Resumen

En el siguiente capítulo encontrás plantillas y checklists listos para usar.