Background y reutilización

Por: Artiko
gherkinbackgrounddryreutilizacion

Background y reutilización

Cuando varios scenarios de una misma feature comparten precondiciones, repetirlas en cada uno viola DRY y dificulta el mantenimiento. Gherkin provee Background para eso.

Sintaxis

Feature: Carrito de compras

  Background:
    Given un cliente registrado con email "[email protected]"
    And la base de datos tiene los productos:
      | sku   | name      | price |
      | P-100 | Mouse     | 25    |
      | P-101 | Keyboard  | 80    |

  Scenario: Agregar producto al carrito
    When ana agrega "P-100" al carrito
    Then el carrito de ana contiene 1 línea

  Scenario: Quitar producto del carrito
    Given ana tiene "P-101" en su carrito con quantity 2
    When ana quita "P-101"
    Then el carrito de ana está vacío

Los steps del Background corren antes de cada scenario de la feature. No es necesario repetirlos.

Cuándo SÍ usar Background

  • Setup de datos comunes: usuarios base, productos, configuraciones que todos los scenarios necesitan.
  • Estado inicial inalterable: el sistema arranca limpio en cada scenario.
  • Contexto del dominio: información que el lector necesita para entender cualquier scenario del archivo.

Cuándo NO usar Background

Antipatrón 1: Background que no aplica a todos los scenarios

Background:
  Given un cliente registrado
- And el cliente tiene una cita agendada para mañana   # ⚠ solo aplica a algunos scenarios

Si la cita agendada no aplica a todos los scenarios, sacala del Background. Movela a los scenarios que la necesitan.

Antipatrón 2: Background con acciones (When)

Background:
  Given un cliente registrado
- When el cliente inicia sesión    # ⚠ When en Background es señal de mal diseño

Background debe contener solo Given. Si el login es precondición para todos los scenarios, expresalo con un Given de más alto nivel:

Background:
  Given un cliente autenticado con email "[email protected]"

La step definition del Given encapsula el “iniciar sesión”.

Antipatrón 3: Background gigante

Background:
- Given un cliente registrado
- And la base de datos tiene 200 productos
- And la base de datos tiene 50 cupones activos
- And la base de datos tiene 10 categorías
- And el servicio de pagos está mockeado
- And el feature flag X está habilitado
- And el feature flag Y está deshabilitado
- And el cache está limpio
- And ...

Si tu Background tiene 10+ steps, probablemente:

  • La feature está sobrecargada (partila en varias)
  • Los Givens son demasiado detallados (subílos un nivel de abstracción)
  • Mezclás setup técnico con setup de dominio

Regla: máximo 3-5 steps en el Background.

Background de bajo nivel vs alto nivel

Bajo nivel (mal):

Background:
  Given existe un registro en la tabla "users" con id 1 y email "[email protected]"
  And existe un registro en la tabla "products" con sku "P-100" y price 25
  And existe un registro en la tabla "products" con sku "P-101" y price 80

Alto nivel (bien):

Background:
  Given un cliente registrado con email "[email protected]"
  And el catálogo tiene los productos:
    | sku   | name      | price |
    | P-100 | Mouse     | 25    |
    | P-101 | Keyboard  | 80    |

El Gherkin debe leerse como lenguaje de dominio, no como SQL.

Background y aislamiento de scenarios

Crítico: cada scenario debe poder ejecutarse en aislamiento. El Background ayuda con el setup, pero si los scenarios dependen del orden de ejecución, hay un bug de diseño.

Scenario: Crear el primer usuario
  When creo un usuario "[email protected]"
  Then existe el usuario "[email protected]"

Scenario: El segundo scenario asume que ana existe
- When ana inicia sesión        # ⚠ depende del scenario anterior
+ # Mover la creación al Background o al Given del scenario

Tests independientes pueden correr en paralelo, en cualquier orden, y son más fáciles de debuggear.

Múltiples Backgrounds

Gherkin permite solo un Background por feature. Si necesitás distinto setup para subgrupos de scenarios, partí la feature en varios archivos:

- features/cart.feature   con 30 scenarios y 1 Background que no aplica a todos
+ features/cart-empty.feature       con scenarios sobre carrito vacío
+ features/cart-with-items.feature  con scenarios sobre carrito con items
+ features/cart-checkout.feature    con scenarios sobre checkout

Cada uno tiene su Background apropiado.

Background en Python (behave) y TS — implementación idéntica

# features/cart.feature

Feature: Carrito
  Background:
    Given un cliente registrado
    And el catálogo tiene 2 productos

  Scenario: Agregar producto
    When agrego "P-100"
    Then el carrito tiene 1 línea
# features/steps/cart.py

@given('un cliente registrado')
def step_register_client(context):
    context.client = Client(email='[email protected]')

@given('el catálogo tiene 2 productos')
def step_seed_products(context):
    context.catalog.add(Product('P-100', 25))
    context.catalog.add(Product('P-101', 80))
// features/step_definitions/cart.ts

Given('un cliente registrado', function () {
  this.client = new Client('[email protected]')
})

Given('el catálogo tiene 2 productos', function () {
  this.catalog.add(new Product('P-100', 25))
  this.catalog.add(new Product('P-101', 80))
})

(En TypeScript, this referencia al World — lo vemos en el capítulo 10.)

Diagrama: ejecución con Background

sequenceDiagram
    participant Cuke as Cucumber
    participant BG as Background steps
    participant S1 as Scenario 1
    participant S2 as Scenario 2

    Cuke->>BG: Ejecutar steps del Background
    BG-->>Cuke: OK
    Cuke->>S1: Ejecutar Scenario 1
    S1-->>Cuke: OK
    Cuke->>BG: Ejecutar steps del Background (otra vez)
    BG-->>Cuke: OK
    Cuke->>S2: Ejecutar Scenario 2
    S2-->>Cuke: OK

El Background corre antes de cada scenario — no una sola vez al inicio.

Tip: combinar con hooks

Background describe setup de dominio (visible para el lector). Hooks (Before/After) describen setup técnico (limpiar DB, levantar mocks). Combinálos:

// hooks
BeforeAll(async () => {
  await dbConnect()
})

Before(async () => {
  await truncateAllTables()
  await seedMinimalData()
})

AfterAll(async () => {
  await dbDisconnect()
})
Background:
  Given un cliente registrado con email "[email protected]"
  And el catálogo tiene 2 productos

Los hooks limpian el ambiente. El Background define el contexto de dominio.

Resumen

  • Background evita repetir precondiciones entre scenarios
  • Máximo 3-5 steps
  • Solo Given (nunca When)
  • Aplica a todos los scenarios de la feature
  • Steps de alto nivel (lenguaje de dominio)
  • No reemplaza hooks técnicos

En el siguiente capítulo vemos Scenario Outline y Examples para parametrizar scenarios.