Testes: sua rede de segurança
Um teste é código que verifica se outro código faz o que você espera. Uma vez escrito, ele roda em segundos e te avisa imediatamente se algo regrediu.
Uma suíte de testes saudável se parece com uma pirâmide: muitos testes unitários pequenos e rápidos na base, menos testes de integração no meio, e apenas um punhado de testes lentos de ponta a ponta no topo. A maior parte da sua segurança vem barata, da base:
╱╲
╱ ╲ E2E few · slow · whole app
╱────╲ (end-to-end)
╱ ╲
╱ INTEG ╲ INTEGRATION some · medium
╱──────────╲ (parts together)
╱ ╲
╱ UNIT ╲ UNIT many · fast · one function
╱────────────────╲
cheap base = most of your tests
Você não precisa de 100% de cobertura. Comece testando as coisas que mais doeriam se quebrassem: login, pagamentos, dados que não podem ser regenerados, a lógica de negócio central. A IA é excelente em escrever testes — muitas vezes melhor do que em escrever funcionalidades, porque o comportamento esperado é concreto.
Aqui está um que funciona bem:
Write tests for the calculateDiscount function in src/pricing.js.
Cover: a normal case, the zero/empty case, the maximum-discount
boundary, and one invalid input. Use the existing test setup in
this repo (check how other *.test.js files are structured).
Run the tests and show me they pass before you finish.
Essa última linha importa. Sempre peça para a IA rodar os testes, não apenas escrevê-los. Um teste que nunca foi executado é um palpite. Também vale a pena ser específico sobre quais casos cobrir, porque, deixada por conta própria, a IA tende a escrever três variações do caminho feliz e chamar isso de completo. Os casos que de fato pegam bugs são os chatos: entrada vazia, o valor limite, a coisa que deveria lançar um erro.
Um exemplo simples do que ela deveria produzir:
import { calculateDiscount } from "./pricing.js";
import { describe, it, expect } from "vitest";
describe("calculateDiscount", () => {
it("applies a normal percentage discount", () => {
expect(calculateDiscount(100, 0.2)).toBe(80);
});
it("returns the full price when discount is zero", () => {
expect(calculateDiscount(100, 0)).toBe(100);
});
it("never discounts below zero", () => {
expect(calculateDiscount(100, 1.5)).toBe(0);
});
it("rejects a negative price", () => {
expect(() => calculateDiscount(-10, 0.2)).toThrow();
});
});
Quando você mudar uma funcionalidade mais tarde, rode os testes primeiro. Se eles ficarem vermelhos, você encontrou a quebra antes dos seus usuários. Quando a IA corrige um bug, peça para ela adicionar um teste que falhe com o comportamento antigo — assim o bug não pode voltar sorrateiramente. Esse hábito tem um nome: teste de regressão. Cada bug que você encontra é uma lição pela qual o código já pagou; um teste de regressão é como você mantém a lição.
Um aviso: um teste também pode estar errado. Se a IA escrever um teste que afirma que o comportamento com bug está correto, ele vai passar para sempre enquanto seu aplicativo continua quebrado. Então leia as asserções, não apenas os checks verdes. Um teste que passa só significa "o código faz o que o teste diz" — você ainda precisa confirmar que o teste diz a coisa certa.