IA no test: gerar testes, validar que não são teatro
5 min de leitura
Você pede pra IA "escreve testes pra essa função". Ela entrega 30 testes verdes. Manda pro CI, merge. Após 1 semana, bug em prod. Pior: os 30 testes que IA gerou não pegam o bug. Esse nó cobre IA no test: como gerar testes úteis, validar que não são "teatro" (testa "implementação" mas não lógica), e garantir que testes pegam bugs reais.
Testes gerados por IA muitas vezes são "happy path only": chamam a função com input válido, esperam output válido, e nada mais. Não testam edge cases, error handling, performance, lógica de negócio. Passar 100% mas não pegar bug real = teatro.
Você sai de "IA gera testes teatro" pra "IA gera testes que pegam bugs reais".
O essencial 🟢
Os 3 tipos de "teste teatro" que IA gera.
-
Happy path only. Testa cenário "input válido → output válido". Não testa input inválido, null, vazio, edge cases.
-
Testa a implementação, não a lógica.
expect(add(1, 2)).toBe(3)- testa que
add(1, 2) === 3, mas não testa que add é comutativa (add(2, 1) === 3).
- testa que
-
Mocka tudo. Mocka database, mocka API, mocka logger - teste vira "testa que o código chama as coisas certas" mas não testa que as coisas funcionam.
Como pedir testes bons pra IA. O prompt certo:
Tarefa: Escreve testes pra função
`validarCpf(cpf: string): boolean`
Contexto:
- Implementação: src/utils/cpf.ts
- Framework: Vitest
Constraints:
- Cobrir edge cases (null, undefined,
string vazia, CPF inválido, CPF com
pontuação, CPF sem pontuação, CPF com
letras no meio)
- Cobrir CPFs válidos conhecidos
(gerar 5+ casos válidos)
- Testar padrões de CPF inválido
conhecidos (todos digitos iguais,
digitos verificadores errados)
- Não mockar nada (função pura)
Verificação:
- 100% de branch coverage
- 0 testes "expect(true).toBe(true)"
- Cada teste testa 1 comportamento
Estrutura de teste bom (AAA).
describe("validarCpf", () => {
// Arrange
// Act
// Assert
it("aceita CPF com pontuação", () => {
expect(validarCpf("123.456.789-09")).toBe(true);
});
it("aceita CPF sem pontuação", () => {
expect(validarCpf("12345678909")).toBe(true);
});
it("rejeita CPF com letras no meio", () => {
expect(validarCpf("123.456.789-0a")).toBe(false);
});
it("rejeita CPF com todos digitos iguais", () => {
expect(validarCpf("111.111.111-11")).toBe(false);
});
it("rejeita CPF com digitos verificadores errados", () => {
expect(validarCpf("123.456.789-00")).toBe(false);
});
it("rejeita string vazia", () => {
expect(validarCpf("")).toBe(false);
});
it("rejeita null/undefined", () => {
expect(validarCpf(null as any)).toBe(false);
expect(validarCpf(undefined as any)).toBe(false);
});
it("rejeita CPF com tamanho errado", () => {
expect(validarCpf("123")).toBe(false);
expect(validarCpf("1234567890123")).toBe(false);
});
});
8 testes = 8 comportamentos. Cada teste tem 1 cenário, 1 expect, resultado claro. Não 30 testes que testam a mesma coisa.
O checklist dos 7 testes "bons".
- Edge cases: null, undefined, "", 0, [], negative, max.
- Caminho feliz: input válido gera output esperado.
- Error handling: input inválido gera error apropriado.
- Boundary: exatamente o limite (ex: 100 chars, não 99 ou 101).
- Estado mutavel: testar antes e depois de mutação.
- Async: testar pending, resolved, rejected.
- Integration: testar interação entre módulos (com mock controlado).
Como detectar "teste teatro".
// ❌ Teatro 1: testa implementação
expect(add(1, 2)).toBe(3); // testa o código
expect(add(2, 1)).toBe(3); // duplicado, mesma lógica
// ❌ Teatro 2: testa truthy
expect(result).toBeTruthy(); // não diz o que é esperado
// ❌ Teatro 3: testa "no throw"
expect(() => fn()).not.toThrow(); // não diz o que deveria fazer
// ❌ Teatro 4: testa "tipo"
expect(typeof result).toBe("string"); // não testa valor
// ❌ Teatro 5: cobre só happy path
expect(validateEmail("user@example.com")).toBe(true);
// ❌ é só 1 teste
Como pedir pra IA gerar testes "bons".
PROMPT MELHORADO:
"Para a função validarCpf em src/utils/cpf.ts,
escreva testes Vitest que cubram:
1. Pelo menos 5 CPFs válidos diferentes
2. Pelo menos 5 CPFs inválidos diferentes
(todos digitos iguais, verificadores errados,
tamanho errado, com letras, vazio)
3. Casos de borda: null, undefined, string
vazia, espacos em branco
4. Para cada cenário, escreva um teste com
expect() claro e descritivo
5. Não use mocks - a função é pura
6. Não escreva testes que apenas verificam
'no throw' ou 'typeof' - cada teste deve
validar um comportamento específico
7. Estruture em blocos describe/it claros"
Teste de mutação: a melhor forma de
validar testes. Mutation testing:
ferramenta Stryker (JS/TS) modifica
o código (troca + por -, > por
<, etc) e roda testes. Se teste
passa com código mutado = teste não
pega o bug. Mutation score 80%+ =
testes bons.
pnpm add -D @stryker-mutator/core @stryker-mutator/vitest-runner
pnpm stryker init
pnpm stryker run
# Stryker reporta: "85% mutation score"
# 15% dos mutantes sobreviveram = teste não pegou
Exemplo de Stryker achando teste fraco.
// Código
if (age >= 18) return "adult";
// Stryker muta pra
if (age > 18) return "adult";
if (age >= 19) return "adult";
if (age > 17) return "adult";
// Se teste passa com QUALQUER desses mutantes
// = teste não testa boundary (age=18)
// Solução: adicionar teste com age=18 explicitamente
Test data builders pra IA. Em vez de "gera 5 inputs válidos", de a IA builder:
// Builder pattern
const cpfValido = (overrides = {}) => ({
cpf: "123.456.789-09",
...overrides,
});
// IA gera 10 CPFs
const cpfs = [
cpfValido({ cpf: "123.456.789-09" }),
cpfValido({ cpf: "987.654.321-00" }),
// ...
];
Builder pattern = IA gera variações sem repetir código.
Aprofundamento 🟡
Quando IA gera testes ruins. Sinais de alerta:
- N coverage report. "Funciona" sem saber quanto foi coberto.
- Testes similares (3+ testes com mesma estrutura, variando só 1 valor).
- Mocks excessivos (>50% do teste é mock).
expect.anything()outoBeDefined()sem contexto.- Teste sem
it()description claro.
Como o IA gera testes bons.
- Especifique o framework (Vitest, Jest, Playwright).
- Especifique o nível (unit, integration, e2e).
- Dê a interface da função (não a implementação).
- Liste edge cases explicitamente.
- Peca branch coverage 100% como constraint.
- Peca mutation score 80%+ como follow-up.
Test pyramid (Martin Fowler).
- 70% unit tests (funções individuais, rápidos, isolados).
- 20% integration tests (módulos juntos, com mock controlado).
- 10% e2e tests (app inteiro, browser, lento).
IA é ótima pra unit tests (escopo claro, input/output definido). Média pra integration (precisa entender módulos). Ruim pra e2e (precisa de browser, timing, async).
TDD com IA - o melhor pattern.
1. Escreve teste (Você):
it("validarCpf aceita CPF válido", () => {
expect(validarCpf("123.456.789-09")).toBe(true);
});
2. Roda teste: FAIL (red) - função não existe
3. Pede implementação (IA):
"Implementa validarCpf em src/utils/cpf.ts
pra fazer o teste passar"
4. IA gera código
5. Roda teste: PASS (green)
6. Refactor (IA ajuda)
7. Adiciona mais testes
8. Repete
TDD = comportamento definido antes, IA gera código que passa teste exato. Menos alucinação porque teste = spec.
Coverage vs Mutation score.
- Coverage: "quantas linhas foram executadas". 90% coverage com testes fracos = "passou em 90% das linhas mas não pegou bugs".
- Mutation score: "quantas variações do código os testes pegam". 80% mutation = bons testes.
Use ambos. Coverage = linha de base (não < 80%). Mutation = qualidade (>= 70%).
Playwright + IA. Em e2e tests, IA ajuda a:
- Gerar
page.goto,page.click,page.fillboilerplate. - MAS não sabe o que testar - você define user journey.
- Review cada step - IA pode
gerar
await page.click('button')sem seletor específico (vai falhar em prod).
Pra quem quer ir mais além 🔴
Property-based testing com fast-check. Em vez de testar inputs específicos, gera inputs aleatórios dentro de propriedades:
import { fc, test } from "fast-check";
test("add é comutativa", () => {
fc.assert(
fc.property(fc.integer(), fc.integer(), (a, b) => {
return add(a, b) === add(b, a);
})
);
});
IA gera 100+ casos aleatórios automaticamente. Mais bugs que testes manuais. Complementa, não substitui, unit tests.
Visual regression testing com
Playwright. Screenshot de pagina
inteira, compara com baseline. IA
ajuda a gerar os expect(page).toHaveScreenshot()
mas review dos baselines é
manual.
Testes de carga (k6, Artillery). IA ajuda a gerar scripts, mas definir carga esperada (1000 RPS? 100?) é business decision.
Mutation testing em CI. Stryker roda em PR (config no GitHub Actions). Falha PR se mutation score < 70%. Força testes bons.
Leitura recomendada:
- Kent C. Dodds - Testing Trophy - balance entre unit/integration/e2e.
- Martin Fowler - Test Pyramid - test pyramid clássico, em 2026 ainda relevante.
Dica: o erro mais comum em "IA no test" é aceitar testes sem validar. IA gera 30 testes verdes = teatro, não qualidade. Valide: (1) Mutation testing (Stryker) - pega testes que não detectam bugs, (2) Coverage 80%+, (3) Edge cases (null, vazio, Unicode), (4) Testa comportamento, não implementação. Sem validação, "100% testes passando" pode ser 100% teatro. 5 min de review por suite = economia de horas em prod.
No próximo nó, vamos IA no refactor: como refatorar com IA sem quebrar comportamento, validar tipos, e identificar quando IA alucina APIs.
// Quiz
O que diferencia um 'teste de IA' útil de 'teste teatro'?