---
title: "Invitado misterioso"
type: "test-smell"
slug: "mystery-guest"
url: "http://localhost:3000/es/test-smells/mystery-guest.md"
category: "Olores de fixtures"
description: "Una prueba cuyas entradas o resultados esperados residen en un recurso externo —un archivo, una semilla de base de datos o una fixture compartida— de modo que no puedes entender ni confiar en la prueba leyéndola por sí sola."
---
# Invitado misterioso

> Una prueba cuyas entradas o resultados esperados residen en un recurso externo —un archivo, una semilla de base de datos o una fixture compartida— de modo que no puedes entender ni confiar en la prueba leyéndola por sí sola.

## Signs and Symptoms

No puedes entender una prueba leyéndola: los datos que la impulsan (y que justifican sus aserciones) residen en algún lugar fuera de la vista —un archivo CSV/JSON, un script de semilla de base de datos, un módulo de fixture compartido o una anotación de fixture de datos del framework—. La prueba hace referencia a un recurso opaco y luego hace aserciones sobre valores «mágicos» cuyo significado está oculto en ese recurso.

Señales reveladoras:

* El cuerpo llama a algo como `readFileSync('fixtures/subscribers.csv')`, `loadSeed('invoices.sql')`, `getResource(...)`, o un `beforeAll` global que siembra una base de datos compartida.
* Los valores esperados parecen arbitrarios (`toHaveLength(3)`, un id/email concreto) y debes abrir otro archivo para averiguar _por qué_.
* Una fixture compartida/«general» se reutiliza en muchas pruebas, de modo que las entradas relevantes para _esta_ prueba quedan enterradas entre datos que no le importan.
* Las pruebas se rompen cuando un compañero edita una fixture compartida para una prueba no relacionada.

```js
test('returns active subscribers', async () => {
  // Invitado misterioso: ¿qué filas hay en este archivo? ¿por qué 3 es correcto?
  const subscribers = await loadSubscribersFromCsv('./fixtures/subscribers.csv');
  const result = filterActive(subscribers);
  expect(result).toHaveLength(3); // la justificación reside fuera de la prueba
});

```

El ejemplo original del catálogo de Meszaros/Test Smells tiene la misma forma: `loadAirportsAndFlightsFromFile("test-flights.csv")` seguido de `assertEquals(1, flightsAtOrigin.size())` —el «1» solo tiene sentido si lees `test-flights.csv`—.

## Reasons for the Problem

**Por qué ocurre**

* _DRY llevado demasiado lejos._ Los datos de prueba se extraen a un archivo compartido o a una «fixture general» para evitar la duplicación, sacrificando legibilidad a cambio de reutilización.
* _Comodidad con datos del mundo real._ Volcar un CSV/JSON de producción o un `seed.sql` parece más fácil que construir objetos en línea.
* _Configuración heredada/de integración._ Las suites que arrancan una base de datos compartida o que dependen de anotaciones de fixtures de datos del framework (`@magentoDataFixture …`) heredan estado oculto por defecto.

**Por qué es perjudicial**

* _Legibilidad / causa y efecto._ El vínculo entre la entrada y la salida esperada se rompe. Un lector no puede ver _por qué_ la aserción es correcta sin salir de la prueba, lo que anula el papel de la prueba como documentación ejecutable.
* _Falsa confianza._ En realidad no sabes qué ejercita la prueba; el archivo puede contener más (o menos) de lo que supones, de modo que una ejecución en verde demuestra menos de lo que parece.
* _Fiabilidad / determinismo._ El recurso externo puede faltar, haber sido renombrado, reformateado o diferir según el entorno, el sistema operativo, la codificación o la configuración regional; los fallos reflejan entonces el estado de la _fixture_, no un defecto real (pruebas inestables).
* _Mantenibilidad / acoplamiento._ Cuando varias pruebas comparten un mismo recurso, cualquiera que lo edite para una prueba puede romper las demás de forma silenciosa, y nadie sabe de qué campos depende cada prueba.

## Treatment

Haz visible la entrada _relevante_ dentro de la prueba, junto a la aserción que depende de ella (una **Fresh Fixture** / configuración en línea). El objetivo es que el valor esperado resulte evidente por sí mismo.

Pasos concretos:

1. **Incorpora en línea los datos que importan.** Construye en el cuerpo de la prueba los pocos objetos/filas que le importan, de modo que el valor esperado de la aserción sea evidentemente correcto.
2. **Si realmente necesitas un archivo, constrúyelo en la prueba.** Usa un helper que reciba solo los parámetros relevantes y escriba en una ruta temporal, y luego limpia; así los valores significativos aparecen en la prueba, no en un bloque versionado.
3. **Sustituye las fixtures compartidas/«generales» por fixtures por prueba**, o expón creadores/buscadores que revelen la intención (`createProductWithName('Simple Product')`, `getRecentlyAddedProduct()`) para que los atributos bajo prueba sean explícitos mientras la configuración irrelevante permanece oculta tras un builder bien nombrado, no tras un recurso opaco.

Antes → después:

```js
// Antes — Invitado misterioso: los datos y el «2» están ocultos en un archivo de semilla
test('flags overdue invoices', async () => {
  await seedDatabaseFromFixture('invoices.sql');
  const overdue = await findOverdueInvoices();
  expect(overdue).toHaveLength(2);
});

// Después — las entradas son visibles; el resultado esperado es obvio
test('flags overdue invoices', async () => {
  await insertInvoice({ id: 1, dueDate: '2020-01-01', paid: false }); // vencida
  await insertInvoice({ id: 2, dueDate: '2099-01-01', paid: false }); // aún no vencida
  const overdue = await findOverdueInvoices();
  expect(overdue.map(i => i.id)).toEqual([1]);
});

```

Para el caso del archivo, prefiere un helper específico antes que un archivo versionado:

```js
const csv = makeSubscriberCsv(tmpFile, 'active@x.com', 'active@y.com', 'active@z.com');
// ahora «3 activos» se justifica por lo que ves en la prueba, no por un archivo oculto

```
