---
title: "Lógica de Teste em Produção"
type: "test-smell"
slug: "test-logic-in-production"
url: "http://localhost:3000/pt-br/test-smells/test-logic-in-production.md"
category: "Maus Cheiros de Acoplamento"
description: "O código de produção contém lógica, ramos ou membros que existem apenas para dar suporte aos testes, borrando a linha entre o que vai para produção e o que é apenas testado."
---
# Lógica de Teste em Produção

> O código de produção contém lógica, ramos ou membros que existem apenas para dar suporte aos testes, borrando a linha entre o que vai para produção e o que é apenas testado.

## Signs and Symptoms

Você encontra código no _sistema sob teste_ (SUT) que só importa quando um teste está rodando. Sinais reveladores:

* **Hooks de teste / flags de modo** — ramos acionados por uma flag `testing`, `isTest`, `NODE_ENV === 'test'` ou `mock` que curto-circuitam o comportamento real.
* **Membros "apenas para testes"** — setters, getters, `reset()` ou construtores públicos adicionados unicamente para que um teste possa alcançar o estado interno, muitas vezes marcados com `@VisibleForTesting` / `@TestOnly` e então de fato chamados pela produção.
* **Poluição de igualdade** — lógica de `equals()` / comparação adicionada a uma classe de produção apenas para que uma asserção possa comparar dois objetos.
* **Dependência de teste em produção** — módulos de produção importando um framework de teste, fixture ou fábrica de mocks.

```ts
// SMELL: o código entregue se comporta de forma diferente quando "testing" está ligado
class PaymentService {
  charge(order: Order) {
    if (process.env.NODE_ENV === 'test' || this.isTesting) {
      return { status: 'ok', id: 'FAKE-TEST-ID' }; // gateway real nunca é exercitado
    }
    return this.gateway.charge(order); // <-- o caminho que realmente vai para produção
  }
}

```

O ramo "real" é aquele que seus clientes atingem, e é exatamente o ramo que seus testes pulam.

## Reasons for the Problem

**Por que acontece**

* O SUT é difícil de testar (ele se comunica com uma rede, relógio, gateway de pagamento ou sistema de arquivos) e adicionar um atalho `if (testing)` é mais rápido do que introduzir uma costura (seam) adequada.
* Um teste precisa observar ou definir o estado interno, então um desenvolvedor o expõe "só para o teste."
* Criar stubs/mocks é trabalhoso, então dados predefinidos são embutidos no código atrás de uma flag.

**Por que prejudica**

* **Falsa confiança.** Os testes exercitam o ramo exclusivo de teste, então o caminho de produção é entregue _sem ser testado_. Testes verdes provam que o fake funciona, não a coisa real.
* **Confiabilidade / segurança.** Código exclusivo de teste que sobrevive até a produção pode rodar em condições reais. A história canônica de advertência de Meszaros é a do Ariane 5: código destinado apenas ao solo, deixado ativo em voo, desencadeou a falha. Um `if (isTesting)` deixado habilitado é a versão em software disso.
* **Segurança.** Desvios de teste são backdoors — uma flag que pula autenticação, pagamento ou validação está a um erro de configuração de distância de se tornar explorável.
* **Legibilidade e inchaço de API.** Setters/getters/`reset()` exclusivos de teste ampliam a superfície pública e enganam os clientes reais sobre para que serve a classe.
* **Manutenibilidade.** Dois comportamentos vivem em uma única classe; toda alteração precisa considerar tanto o caminho de produção quanto o de teste, e a divergência apodrece silenciosamente.

## Treatment

Tire a lógica de teste do código de produção introduzindo uma _costura_ (seam) adequada em vez de uma flag.

1. **Injete a variação (Injeção de Dependência + Test Double).** Substitua o ramo embutido por um colaborador que o teste substitui. A produção conecta a implementação real; o teste conecta um fake/stub/mock.
2. **Use uma Subclasse Específica para Teste** quando você só precisa sobrescrever um método — sobrescreva-o em uma subclasse que vive no código de teste, e não por meio de um `if` na classe base.
3. **Aplique o padrão Humble Object** para puxar a lógica difícil de testar (relógio, E/S) para trás de um adaptador fino, de modo que a lógica central se torne diretamente testável sem hooks.
4. **Mova a lógica de comparação para o lado do teste.** Em vez de poluir a produção com `equals()` para asserções, use um matcher/comparador personalizado ou faça asserções sobre os campos que importam para você.
5. **Mantenha o código de teste fora do build.** Use separação de source-set / configuração de build para que os helpers de teste não possam ser compilados no artefato entregue; marque os membros genuinamente visíveis para teste com `@VisibleForTesting`/`@TestOnly` e deixe um linter garantir que a produção nunca os chame.

```ts
// ANTES: hook de teste dentro do código de produção
class PaymentService {
  charge(order: Order) {
    if (this.isTesting) return { status: 'ok', id: 'FAKE-TEST-ID' };
    return this.gateway.charge(order);
  }
}

// DEPOIS: um único caminho de código; o gateway é injetado e simulado no teste
class PaymentService {
  constructor(private gateway: PaymentGateway) {}
  charge(order: Order) {
    return this.gateway.charge(order); // mesmo caminho em produção e em teste
  }
}

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

```

Agora o caminho de produção é o _único_ caminho, e o teste controla o comportamento de fora.

## Detected by

- **codeql** `java/visible-for-testing-abuse` — Uso de VisibleForTesting em código de produção (https://codeql.github.com/codeql-query-help/java/java-visible-for-testing-abuse/)
- **deepsource** `JAVA-A1067` — Métodos @VisibleForTesting/@TestOnly não devem ser usados em código que não seja de teste (https://deepsource.com/directory/java/issues/JAVA-A1067)
- **android-lint** `VisibleForTests` — Visível Apenas Para Testes (https://googlesamples.github.io/android-custom-lint-rules/checks/VisibleForTests.md.html)
