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

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:

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

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