---
title: "Teste Obscuro"
type: "test-smell"
slug: "obscure-test"
url: "http://localhost:3000/pt-br/test-smells/obscure-test.md"
category: "Maus Cheiros Obscuros"
description: "Um Teste Obscuro é aquele em que o leitor não consegue dizer, apenas pelo método de teste, qual cenário é montado, qual comportamento é exercitado e qual resultado é esperado — porque a intenção está soterrada em detalhes demais, contexto de menos ou lógica escondida em outro lugar."
---
# Teste Obscuro

> Um Teste Obscuro é aquele em que o leitor não consegue dizer, apenas pelo método de teste, qual cenário é montado, qual comportamento é exercitado e qual resultado é esperado — porque a intenção está soterrada em detalhes demais, contexto de menos ou lógica escondida em outro lugar.

## Signs and Symptoms

Você lê um teste e ainda não consegue responder a três perguntas: _qual é a configuração, o que está sendo exercitado e qual é o resultado esperado?_ A cadeia de causa/efeito está escondida. Meszaros agrupa as causas em "informação demais" e "informação de menos". Sinais comuns:

* **Eager Test** — um único método de teste verifica muitos comportamentos não relacionados, de modo que nenhuma intenção isolada fica clara.
* **Mystery Guest** — o fixture ou os valores esperados vivem fora do teste (um arquivo, um registro de banco compartilhado, um fixture carregado por nome), então você não consegue ver por que a asserção deveria passar.
* **General Fixture** — um grande `beforeEach`/factory compartilhado constrói muito mais do que este teste precisa; os poucos campos relevantes se perdem no ruído.
* **Informação Irrelevante** — páginas de dados de configuração ou um snapshot gigante em que apenas um ou dois campos de fato importam.
* **Dados de Teste Hard-Coded** — literais mágicos (`42`, `"a3f9-..."`, `userId=7`) sem significado nomeado, repetidos na configuração e nas asserções.
* **Indirect Testing** — o teste cutuca o sistema sob teste por meio de vários outros objetos, obscurecendo o que realmente está sob teste.

```js
// Obscuro: Eager + Mystery Guest + Informação Irrelevante
test('user', async () => {
  const data = loadFixture('users.json');        // mystery guest: os valores vivem em um arquivo
  const svc = new UserService(data, cfg, clock); // general fixture: a maior parte disto não é usada
  const u = await svc.create({ ...data[0], roles: ['a','b'], flags: 0x1f });

  expect(u.id).toBeDefined();
  expect(u.email).toContain('@');
  expect(await svc.count()).toBe(data.length + 1); // por que esse número? a resposta está no arquivo
  expect(await svc.login(u.email, 'p@ss')).toBe(true); // segundo comportamento não relacionado
});

```

Aqui você não consegue dizer o que o teste prova sem abrir `users.json`, e na verdade ele verifica criação _e_ login de uma só vez.

## Reasons for the Problem

**Por que acontece**

* Os testes crescem por acúmulo: um desenvolvedor adiciona "mais uma asserção" a um teste existente em vez de escrever um novo, produzindo um Eager Test.
* Compartilhar a configuração parece eficiente, então um único fixture amplo ou `beforeEach` é reutilizado em todo lugar (General Fixture), e arquivos externos/seeds de banco são carregados por nome (Mystery Guest).
* Copiar e colar dados de aparência realista arrasta dezenas de campos irrelevantes e números mágicos.
* Excesso de mocking ou passar por muitos colaboradores transforma um teste de unidade em Indirect Testing.

**Por que isso prejudica**

* **Legibilidade:** um teste é a documentação do comportamento pretendido. Se o leitor não consegue reconstruir Setup → Exercício → Verificação, esse valor de documentação se perde.
* **Manutenibilidade:** quando um teste obscuro falha, você não sabe qual comportamento quebrou ou se o erro está no teste ou no código, então as mudanças são lentas e arriscadas.
* **Confiabilidade:** Mystery Guest e General Fixture acoplam o teste a estado externo/compartilhado, causando falhas instáveis ou dependentes de ordem (e quebrando a propriedade "fresca e determinística" de um bom teste de unidade).
* **Falsa confiança:** Eager Tests mascaram a cobertura — uma falha no início do método interrompe as verificações posteriores, então comportamentos que você _pensa_ estarem testados podem nunca rodar. E, como observa Meszaros, erros de programação são mais fáceis de esconder em um teste obscuro, produzindo Buggy Tests que passam pelos motivos errados.

## Treatment

Faça com que todo teste conte uma história autocontida cuja intenção fique visível no corpo do teste.

1. **Verifique uma condição por teste.** Divida um Eager Test em testes focados, cada um nomeado pelo comportamento que verifica. Isso também corrige o mascaramento de cobertura.
2. **Coloque o fixture relevante inline (elimine o Mystery Guest).** Construa os dados de que o teste depende _no próprio teste_, ou por meio de um método Creation/Builder explícito e nomeado — não carregue arquivos anônimos nem linhas de banco compartilhadas.
3. **Use um Fixture Mínimo / Fresco.** Construa apenas o que este teste precisa; substitua um `beforeEach` amplo e compartilhado por um builder que define valores padrão para o ruído e deixa cada teste definir apenas o campo sob teste.
4. **Nomeie seus dados.** Substitua literais mágicos por constantes/variáveis que revelem a intenção, de modo que a asserção se explique por si só.
5. **Afirme sobre o significado, não sobre tudo.** Prefira asserções direcionadas a um snapshot gigante; se usar snapshot, mantenha-o pequeno e revisável para que os fatos relevantes não se afoguem em saída irrelevante.
6. **Esconda a mecânica, não a intenção.** Empurre a fiação incidental para métodos Test Utility/auxiliares bem nomeados, de modo que o corpo do teste se leia como configuração → ação → expectativa.

```js
// Antes (obscuro)
test('user', async () => {
  const data = loadFixture('users.json');
  const svc = new UserService(data, cfg, clock);
  const u = await svc.create({ ...data[0], roles: ['a','b'], flags: 0x1f });
  expect(await svc.count()).toBe(data.length + 1);
});

// Depois: uma intenção, fixture inline, dados nomeados
test('create() persists a new user', async () => {
  const svc = userServiceWith([]);                 // fixture mínimo e fresco
  const newUser = aUser({ email: 'ada@example.com' }); // o builder define valores padrão para o ruído

  const created = await svc.create(newUser);

  expect(created.email).toBe('ada@example.com');
  expect(await svc.count()).toBe(1);               // autoexplicativo, sem arquivo externo
});

```

Busque o formato AAA (Arrange-Act-Assert): o leitor deve compreender o cenário sem sair do método de teste.

## Detected by

- **eslint-plugin-jest** `max-expects` — jest/max-expects (https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/max-expects.md)
- **eslint-plugin-vitest** `max-expects` — vitest/max-expects (https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/max-expects.md)
- **eslint-plugin-jest** `no-large-snapshots` — jest/no-large-snapshots (https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-large-snapshots.md)
- **eslint-plugin-vitest** `no-large-snapshots` — vitest/no-large-snapshots (https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-large-snapshots.md)
- **eslint-plugin-jest** `max-nested-describe` — jest/max-nested-describe (https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/max-nested-describe.md)
