---
title: "Lógica de Prueba en Producción"
type: "test-smell"
slug: "test-logic-in-production"
url: "http://localhost:3000/es/test-smells/test-logic-in-production.md"
category: "Olores de acoplamiento"
description: "El código de producción contiene lógica, ramas o miembros que existen únicamente para dar soporte a las pruebas, difuminando la línea entre lo que se entrega y lo que solo se prueba."
---
# Lógica de Prueba en Producción

> El código de producción contiene lógica, ramas o miembros que existen únicamente para dar soporte a las pruebas, difuminando la línea entre lo que se entrega y lo que solo se prueba.

## Signs and Symptoms

Encuentras código en el _sistema bajo prueba_ (SUT) que solo importa cuando se ejecuta una prueba. Señales reveladoras:

* **Ganchos de prueba / banderas de modo**: ramas condicionadas por una bandera `testing`, `isTest`, `NODE_ENV === 'test'` o `mock` que cortocircuitan el comportamiento real.
* **Miembros "solo para pruebas"**: setters públicos, getters, `reset()` o constructores añadidos únicamente para que una prueba pueda alcanzar el estado interno, a menudo etiquetados con `@VisibleForTesting` / `@TestOnly` y luego en realidad llamados desde producción.
* **Contaminación de igualdad**: lógica `equals()` / de comparación añadida a una clase de producción únicamente para que una aserción pueda comparar dos objetos.
* **Dependencia de prueba en producción**: módulos de producción que importan un framework de pruebas, un fixture o una fábrica de mocks.

```ts
// OLOR: el código entregado se comporta de forma distinta cuando "testing" está activo
class PaymentService {
  charge(order: Order) {
    if (process.env.NODE_ENV === 'test' || this.isTesting) {
      return { status: 'ok', id: 'FAKE-TEST-ID' }; // la pasarela real nunca se ejercita
    }
    return this.gateway.charge(order); // <-- la ruta que realmente se entrega
  }
}

```

La rama "real" es la que tus clientes utilizan, y es exactamente la rama que tus pruebas omiten.

## Reasons for the Problem

**Por qué ocurre**

* El SUT es difícil de probar (se comunica con una red, un reloj, una pasarela de pago o el sistema de archivos) y añadir un atajo `if (testing)` es más rápido que introducir una costura adecuada.
* Una prueba necesita observar o establecer un estado interno, así que un desarrollador lo expone "solo para la prueba".
* Crear stubs/mocks resulta incómodo, así que se codifican datos predefinidos detrás de una bandera.

**Por qué es perjudicial**

* **Falsa confianza.** Las pruebas ejercitan la rama exclusiva de prueba, por lo que la ruta de producción se entrega _sin probar_. Las pruebas verdes demuestran que el simulacro funciona, no la realidad.
* **Fiabilidad / seguridad.** El código exclusivo de prueba que sobrevive hasta producción puede ejecutarse en condiciones reales. La advertencia canónica de Meszaros es el Ariane 5: un código destinado solo a tierra que quedó activo en vuelo provocó el fallo. Un `if (isTesting)` dejado habilitado es la versión software de eso.
* **Seguridad.** Los atajos de prueba son puertas traseras: una bandera que omite la autenticación, el pago o la validación está a un error de configuración de ser explotable.
* **Legibilidad e hinchazón de la API.** Los setters/getters/`reset()` exclusivos de prueba agrandan la superficie pública e inducen a error a los clientes reales sobre para qué sirve la clase.
* **Mantenibilidad.** Dos comportamientos conviven en una misma clase; cada cambio debe razonar tanto sobre la ruta de producción como sobre la de prueba, y la divergencia se va pudriendo en silencio.

## Treatment

Saca la lógica de prueba del código de producción introduciendo una _costura_ adecuada en lugar de una bandera.

1. **Inyecta la variación (Inyección de Dependencias + Doble de Prueba).** Reemplaza la rama codificada de forma fija por un colaborador que la prueba sustituye. En producción se conecta la implementación real; en la prueba se conecta un fake/stub/mock.
2. **Usa una Subclase Específica de Prueba** cuando solo necesites sobrescribir un método: sobrescríbelo en una subclase que viva en el código de prueba, no mediante un `if` en la clase base.
3. **Aplica el patrón Humble Object** para llevar la lógica difícil de probar (reloj, E/S) detrás de un adaptador fino, de modo que la lógica central se vuelva directamente comprobable sin ganchos.
4. **Mueve la lógica de comparación al lado de la prueba.** En lugar de contaminar producción con `equals()` para las aserciones, usa un matcher/comparador personalizado o afirma sobre los campos que te interesan.
5. **Mantén el código de prueba fuera de la compilación.** Usa separación de source-sets / configuración de compilación para que los ayudantes de prueba no puedan compilarse en el artefacto entregado; marca los miembros que de verdad deban ser visibles para las pruebas con `@VisibleForTesting`/`@TestOnly` y deja que un linter haga cumplir que producción nunca los llame.

```ts
// ANTES: gancho de prueba dentro del código de producción
class PaymentService {
  charge(order: Order) {
    if (this.isTesting) return { status: 'ok', id: 'FAKE-TEST-ID' };
    return this.gateway.charge(order);
  }
}

// DESPUÉS: una única ruta de código; la pasarela se inyecta y se simula en la prueba
class PaymentService {
  constructor(private gateway: PaymentGateway) {}
  charge(order: Order) {
    return this.gateway.charge(order); // la misma ruta en producción y en prueba
  }
}

// prueba
const fakeGateway = { charge: () => ({ status: 'ok', id: 'FAKE-TEST-ID' }) };
const service = new PaymentService(fakeGateway);

```

Ahora la ruta de producción es la _única_ ruta, y la prueba controla el comportamiento desde fuera.

## Detected by

- **codeql** `java/visible-for-testing-abuse` — Uso de VisibleForTesting en código de producción (https://codeql.github.com/codeql-query-help/java/java-visible-for-testing-abuse/)
- **deepsource** `JAVA-A1067` — Los métodos @VisibleForTesting/@TestOnly no deben usarse en código que no sea de prueba (https://deepsource.com/directory/java/issues/JAVA-A1067)
- **android-lint** `VisibleForTests` — Visible solo para pruebas (https://googlesamples.github.io/android-custom-lint-rules/checks/VisibleForTests.md.html)
