Front End

31 mar, 2026

Refatoramos 200 testes inúteis e ficamos com 30 melhores

Publicidade

Todo mundo já passou por isso: você entra em um projeto com mais de 200 testes, pipeline verde, cobertura alta e mesmo assim… bugs passam, deploy dá medo e ninguém confia nos testes.

Foi exatamente esse cenário que enfrentamos. E a solução não foi escrever mais testes. Foi fazer o oposto: apagar a maioria deles.

O problema: muitos testes, pouca confiança

O projeto tinha: 212 testes, 87% de cobertura e tempo de execução alto. Mas na prática: qualquer refactor quebrava tudo, além de ter snapshots gigantes, mocks irreais e testes acoplados à implementação

Exemplo real (antes)

import { render } from '@testing-library/react';
import UserCard from './UserCard';

test('renderiza corretamente', () => {
  const { container } = render(
    <UserCard user={{ id: 1, name: 'Rafa' }} />
  );

  expect(container).toMatchSnapshot();
});

Problemas:

  • snapshot enorme
  • difícil revisar
  • não testa comportamento

👉 só garante que nada mudou (ou finge garantir)

A decisão radical: reduzir para o essencial

Antes de sair refatorando, definimos uma regra simples:

“Se o teste não pega bug real, ele não deveria existir.”

Simples. E doloroso.

Etapa 1: deletar snapshots sem valor

Removemos quase todos.

De mais ou menos 80 snapshots, sobraram 5.

O que entrou no lugar

import { render, screen } from '@testing-library/react';

test('exibe nome do usuário', () => {
  render(<UserCard user={{ id: 1, name: 'Rafa' }} />);

  expect(screen.getByText('Rafa')).toBeInTheDocument();
});

Agora:

  • teste legível
  • fácil manutenção
  • valida algo real

Etapa 2: parar de testar implementação

Esse foi o maior ganho. 😀

Antes (acoplado)

test('usa classe correta', () => {
  const { container } = render(<Button />);

  expect(container.firstChild).toHaveClass('btn-primary');
});

Depois (comportamento)

import userEvent from '@testing-library/user-event';

test('dispara ação ao clicar', async () => {
  const onClick = jest.fn();

  render(<Button onClick={onClick}>Salvar</Button>);

  await userEvent.click(screen.getByText('Salvar'));

  expect(onClick).toHaveBeenCalled();
});

👉 o teste sobrevive a refactor

Etapa 3: eliminar mocks mentirosos

Tínhamos vários testes assim:

jest.mock('./api', () => ({
  fetchUsers: () => Promise.resolve([{ id: 1, name: 'Fake' }]),
}));

Problema:

👉 testava um mundo que não existe

Solução com MSW (mock realista)

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  rest.get('/api/users', (req, res, ctx) => {
    return res(
      ctx.json([
        { id: 1, name: 'Rafa' },
        { id: 2, name: 'Dev' },
      ])
    );
  })
);

beforeAll(() => server.listen());
afterAll(() => server.close());

Agora:

  • simula API real
  • mantém consistência
  • reduz surpresas

Etapa 4: focar em fluxos reais

Paramos de testar funções isoladas. E começamos a testar o sistema.

Exemplo (login real)

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Login from './Login';

test('usuário consegue logar', async () => {
  render(<Login />);

  await userEvent.type(screen.getByLabelText('Email'), 'teste@email.com');
  await userEvent.type(screen.getByLabelText('Senha'), '123456');

  await userEvent.click(screen.getByRole('button', { name: 'Entrar' }));

  expect(await screen.findByText('Bem-vindo')).toBeInTheDocument();
});

👉 isso pega bug de verdade

Etapa 5: adicionar poucos testes E2E (mas certos)

Usamos Playwright.

Exemplo de fluxo crítico

import { test, expect } from '@playwright/test';

test('fluxo de checkout', async ({ page }) => {
  await page.goto('http://localhost:3000');

  await page.click('text=Produtos');
  await page.click('text=Adicionar ao carrinho');

  await page.click('text=Finalizar compra');

  await expect(page.locator('h1')).toHaveText('Pedido confirmado');
});

👉 apenas 5 testes E2E cobriram o essencial

Resultado final (de verdade)

Antes:

  • 212 testes
  • execução: 9 minutos
  • baixa confiança

Depois:

  • 34 testes
  • execução: 2 minutos
  • alta confiança

E o mais importante

  • menos falsos positivos
  • menos manutenção
  • mais segurança para deploy

O que aprendemos (na prática)

1. Cobertura alta pode ser enganosa

2. Snapshot é muleta (na maioria dos casos)

3. Mock mal feito cria ilusão

4. Teste bom é o que pega bug real

A regra que ficou

Se o teste não responde:

👉 “isso quebraria em produção?”

Ele provavelmente não deveria existir.

Conclusão: menos teste, mais valor

A maior virada não foi técnica, foi mental. Paramos de medir quantidade e cobertura. E começamos a medir confiança e utilidade

No final do dia, Dev Sênior tem que escrever os testes certos. E isso impacta diretamente a velocidade, a segurança e a maturidade do seu time.