---
title: "Testando Detalhes de Implementação"
type: "test-smell"
slug: "testing-implementation-details"
url: "http://localhost:3000/pt-br/test-smells/testing-implementation-details.md"
category: "Maus Cheiros de Mocking"
description: "Um teste faz asserções sobre como o código funciona internamente — campos privados, chamadas a métodos internos, estrutura do DOM ou classes CSS — em vez do comportamento observável do qual um consumidor real depende."
---
# Testando Detalhes de Implementação

> Um teste faz asserções sobre como o código funciona internamente — campos privados, chamadas a métodos internos, estrutura do DOM ou classes CSS — em vez do comportamento observável do qual um consumidor real depende.

## Signs and Symptoms

Você reconhece este sintoma quando um teste vai _além_ do contrato público e fixa a maquinaria por trás dele. Sinais comuns:

* Asserções sobre **estado/campos internos ou privados**, ou invocação direta de métodos privados (muitas vezes via casts, reflexão ou `// @ts-expect-error`).
* Espionar ou afirmar que um **helper interno foi chamado** (`expect(internalCalc).toHaveBeenCalled()`) em vez de verificar o resultado.
* Testes de UI que consultam por **classe CSS, tag, hooks `data-*` ou posição no DOM** em vez de por role/label/texto — por exemplo `container.querySelector('.btn-primary > span:nth-child(2)')`, `wrapper.state()`, `wrapper.find('SomeChildComponent').props()`.
* Testes de snapshot sobre **árvores de renderização inteiras / objetos internos serializados**, de modo que qualquer ajuste de marcação falha.
* Testes que **quebram a cada refatoração** mesmo que a funcionalidade continue funcionando (falsos negativos) e, inversamente, continuam passando após um bug de lógica porque apenas reverificam a ligação interna (falsos positivos).

```js
// SMELL: acopla o teste aos internos do componente e à estrutura do DOM
test('counter increments', () => {
  const wrapper = mount(<Counter />);
  wrapper.instance().handleClick();          // chama um método privado diretamente
  expect(wrapper.state('count')).toBe(1);    // faz asserção sobre estado interno
  expect(wrapper.find('.count-display').text()).toBe('1'); // seletor CSS frágil
});

```

O mesmo padrão aparece no lado servidor: `expect(service._cache.size).toBe(1)` ou afirmar a sequência exata de chamadas internas que um método faz.

## Reasons for the Problem

**Por que acontece**

* O estado interno é _fácil de alcançar_ — um campo público, um helper exportado ou `container.querySelector` está logo ali, enquanto exercitar o comportamento real exige mais preparação.
* Perseguir métricas de cobertura: testar cada método privado 1:1 dá a sensação de minuciosidade.
* O uso excessivo de mocks empurra as pessoas a afirmar "este colaborador foi chamado" em vez de "a coisa certa aconteceu."
* Ferramentas que incentivam isso: shallow rendering / APIs `instance()` / `state()`, ou capturar nós pelo nome da classe.

**Por que é prejudicial**

* **Manutenibilidade / fragilidade.** Este é o _Teste Frágil_ de Meszaros, causado por _Software Superespecificado_: o teste fixa um comportamento que o consumidor nunca exigiu, de modo que refatorações inofensivas (renomear um método, reestruturar a marcação, alterar um campo privado) quebram testes que estavam verdes sem motivo real. Os testes se tornam um imposto sobre a refatoração em vez de uma rede de segurança.
* **Falsa confiança (o perigo central, segundo Kent C. Dodds).** Testes de detalhes de implementação falham nas _duas_ direções erradas: **falsos negativos** (o teste fica vermelho embora a funcionalidade ainda funcione) e **falsos positivos** (o teste permanece verde embora a funcionalidade esteja quebrada — você verificou a ligação interna, não o resultado). De qualquer forma, a suíte deixa de lhe dizer a verdade.
* **Legibilidade.** O teste documenta _como_ o código é construído, não _o que ele garante_. Quem lê não consegue identificar qual comportamento realmente importa, e o teste deixa de servir também como exemplo de uso ou especificação.
* **Acoplamento.** Ele fixa as decisões de design atuais, desencorajando exatamente as refatorações que os testes deveriam tornar seguras.

## Treatment

Teste através do **contrato público** — a mesma superfície que um chamador ou usuário real toca — e faça asserções sobre a **saída observável**: valores de retorno, erros lançados, eventos emitidos, estado persistido ou UI renderizada/visível.

1. **Identifique o consumidor.** Para um módulo, é sua API exportada; para um componente de UI, é o usuário (cliques, digitação) e o que ele consegue ver.
2. **Forneça as entradas como um consumidor faria**, e não chamando métodos privados. Dispare um clique real em vez de invocar o handler; chame o método público em vez do helper.
3. **Faça asserções sobre resultados, não sobre internos.** Substitua verificações de `state()`/campo privado/`toHaveBeenCalled` por verificações sobre o que sai.
4. **Consulte a UI por acessibilidade, não por estrutura** — role, label, texto — em vez de classes CSS, tags ou `nth-child`.
5. **Pare de testar métodos privados diretamente.** Cubra-os através do método público que os utiliza; se uma unidade privada for complexa o suficiente para precisar de seus próprios testes, isso é um sinal de que ela deve ser extraída para seu próprio módulo com sua própria API pública.
6. **Reserve asserções de mock/spy para fronteiras verdadeiras** (rede, tempo, gateway de pagamento) onde a _própria chamada_ é o comportamento observável — não para colaboradores internos.

```js
// ANTES: testa detalhes de implementação
const wrapper = mount(<Counter />);
wrapper.instance().handleClick();
expect(wrapper.state('count')).toBe(1);
expect(wrapper.find('.count-display').text()).toBe('1');

// DEPOIS: testa o comportamento observável via contrato público voltado ao usuário
render(<Counter />);
await userEvent.click(screen.getByRole('button', { name: /increment/i }));
expect(screen.getByText('1')).toBeInTheDocument();

```

Regra prática: se uma refatoração que preserva o comportamento quebra o teste, o teste estava verificando um detalhe de implementação.

## Detected by

- **eslint-testing-library** `testing-library/no-node-access` — no-node-access (https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-node-access.md)
- **eslint-testing-library** `testing-library/no-container` — no-container (https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-container.md)
