---
title: "Inicialización en el constructor"
type: "test-smell"
slug: "constructor-initialization"
url: "http://localhost:3000/es/test-smells/constructor-initialization.md"
category: "Olores de fixtures"
description: "Una clase de test inicializa los campos de su fixture en un constructor en lugar de en el hook de configuración dedicado del framework (setUp / @BeforeEach / TestInitialize), saltándose el ciclo de vida del test."
---
# Inicialización en el constructor

> Una clase de test inicializa los campos de su fixture en un constructor en lugar de en el hook de configuración dedicado del framework (setUp / @BeforeEach / TestInitialize), saltándose el ciclo de vida del test.

## Signs and Symptoms

Una clase de test tiene un constructor explícito que construye el sistema bajo prueba, los mocks o los campos compartidos —trabajo que corresponde al hook de configuración del framework (`setUp()` / `@Before` / `@BeforeEach` en JUnit, `[TestInitialize]` en MSTest, `beforeEach` en Jest/Vitest)—.

Señales reveladoras:

* La clase de test declara un constructor que asigna a campos `final`/de instancia.
* La configuración del fixture vive fuera del ciclo de vida que el framework gestiona realmente, de modo que `@BeforeEach`/`@AfterEach`, la configuración de la clase base y la reinicialización por test se saltan silenciosamente o se ejecutan en un orden confuso respecto al constructor.
* La configuración asíncrona es imposible: no puedes usar `await` dentro de un constructor, así que el trabajo de fixture asíncrono se ve forzado al lugar equivocado o se duplica.

Forma canónica en JUnit (del catálogo de test smells):

```java
public class TagEncodingTest extends BrambleTestCase {
    private final CryptoComponent crypto;
    private final SecretKey tagKey;

    public TagEncodingTest() {                 // mal olor: inicialización en el constructor
        crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
        tagKey = TestUtils.getSecretKey();
    }
}

```

Análogo en JS/TS: el fixture se construye una sola vez en el ámbito de `describe`/módulo (el equivalente al constructor) en lugar de por test:

```ts
describe('Cart', () => {
  const cart = new Cart();          // se construye una vez, filtra estado entre tests
  it('adds an item', () => { cart.add(apple); expect(cart.size).toBe(1); });
  it('starts empty', () => { expect(cart.size).toBe(0); }); // falla: ve apple
});

```

## Reasons for the Problem

**Por qué ocurre**

* Las personas desarrolladoras que no conocen el propósito del hook de configuración recurren a la característica del lenguaje que ya conocen —el constructor— para inicializar los campos.
* Parece más limpio: los campos `final` junto con un constructor resultan idiomáticos, e incluso un IDE puede generar el constructor por ti.
* Imitación acrítica (cargo cult) de las clases de producción, donde la inicialización en el constructor _sí_ es el patrón correcto.

**Por qué es perjudicial**

* **Se salta el ciclo de vida del test.** Los frameworks prometen un estado fresco por test mediante el hook de configuración y un par `@BeforeEach`/`@AfterEach` (o `beforeEach`/`afterEach`). La lógica oculta en un constructor queda fuera de ese contrato, así que la limpieza, la configuración de la clase base y las garantías de orden pueden no aplicarse como se espera.
* **Fuga de estado e inestabilidad.** En los frameworks que reutilizan una sola instancia (o cuando guardas el fixture en una variable compartida o con ámbito de `describe`), las mutaciones de un test se filtran al siguiente. Los tests pasan o fallan según el orden de ejecución: falsa confianza y fallos intermitentes.
* **Sin configuración asíncrona.** Un constructor no puede usar `await`. Cualquier configuración que necesite E/S, una conexión a BD o un servidor arrancado no puede vivir ahí de forma limpia; la gente lo sortea con llamadas bloqueantes o con código duplicado por test.
* **Legibilidad/consistencia.** Los revisores y las herramientas esperan los fixtures en el hook convencional. Repartir la inicialización entre un constructor y un método de configuración hace que el fixture real sea difícil de encontrar y fácil de equivocar.

**Advertencia: depende del framework.** Esto no es una regla universal. En **xUnit.net** el constructor _es_ la configuración idiomática por test (emparejado con `IDisposable` para el teardown), y MSTest incluso incluye una regla opuesta y opcional (`MSTEST0020`) que prefiere los constructores frente a `[TestInitialize]`. Considera «Constructor Initialization» un mal olor específicamente cuando tu framework proporciona un hook de configuración dedicado (JUnit, MSTest clásico, NUnit) y lo estás evitando.

## Treatment

Saca la inicialización de campos del constructor y llévala al hook de configuración del framework, y prefiere un estado fresco por test antes que instancias compartidas.

1. Elimina el constructor de la clase de test; declara los campos y asígnalos en el hook de configuración (`@BeforeEach`/`setUp()` para JUnit, `[TestInitialize]` para MSTest, `beforeEach` para Jest/Vitest).
2. Si la configuración es asíncrona, esto es obligatorio: el hook puede usar `await`; un constructor no.
3. En JS/TS, construye el fixture _dentro_ de `beforeEach` (reasignando un `let`) en lugar de una sola vez en el ámbito de `describe`/módulo, de modo que cada test reciba un objeto limpio.
4. Mantén el teardown simétrico: empareja `@BeforeEach` con `@AfterEach` (o, en el estilo de constructor de xUnit.net, implementa `IDisposable`).

Antes → después (JUnit):

```java
// antes
public class TagEncodingTest {
    private final CryptoComponent crypto = new CryptoComponentImpl(...);
}

// después
public class TagEncodingTest {
    private CryptoComponent crypto;

    @BeforeEach
    void setUp() {
        crypto = new CryptoComponentImpl(...);
    }
}

```

Antes → después (Jest/Vitest):

```ts
describe('Cart', () => {
  let cart: Cart;
  beforeEach(() => { cart = new Cart(); }); // fresco por test
  it('adds an item', () => { cart.add(apple); expect(cart.size).toBe(1); });
  it('starts empty', () => { expect(cart.size).toBe(0); });
});

```

Si el fixture es genuinamente inmutable y costoso (y tu framework lo admite), un hook de una sola vez como `@BeforeAll`/`beforeAll` es aceptable, pero solo para estado compartido verdaderamente de solo lectura, nunca para objetos que los tests mutan.

## Detected by

- **tsDetect (Test Smell Detector)** `Constructor Initialization` (https://testsmells.org/pages/testsmells.html)
- **MSTest Roslyn analyzers** `MSTEST0019` (https://learn.microsoft.com/en-us/dotnet/core/testing/mstest-analyzers/mstest0019)
