No início de 2022, tomei uma decisão silenciosa: parei de escrever testes unitários para a maioria dos projetos WordPress e Node passando pela Seahawk. Não abertamente. Sem post de blog sobre isso. Eu apenas... parei. A justificativa parecia sólida, pensei — estávamos entregando de 15 a 20 sites de clientes por mês, eu tinha três outros desenvolvedores em rodízio, e os testes que eu escrevia pareciam documentação que ninguém lia. QA manual capturava os bugs reais. Testes eram teatro.
Avançando para o final de 2023. GitHub Copilot estava no meu editor há cerca de oito meses. Eu também tinha começado a usar Cursor em paralelo para qualquer coisa greenfield. A velocidade era genuinamente notável. Mas algo começou a acontecer. Bugs apareciam em lugares que eu não tinha tocado. Lógica que parecia correta estava errada em edge cases que eu nunca pensei em verificar. E o pior — a IA não tinha ideia de que estava errada. Ela escrevia o código quebrado com a mesma indentação confiante de sempre.Cursor on the side for anything greenfield. The speed was genuinely remarkable. But something started happening. Bugs were appearing in places I hadn't touched. Logic that looked correct was wrong in edge cases I'd never thought to check. And the worst part — the AI had no idea it was wrong. It wrote the broken code with the same confident indentation it always does.
Foi aí que peguei os testes de novo.
---
O Período em que Larguei os Testes (E Por que Fazia Sentido Na Época)
Resposta honesta? Para um certo tipo de projeto, pular testes foi a decisão certa. Se você está construindo um site de brochura de cinco páginas em WordPress, escrever testes PHPUnit para um plugin de formulário de contato é teatro. Defendo isso.was the right call. If you're building a five-page brochure site in WordPress, writing PHPUnit tests for a contact form plugin is theatre. I stand by that.
O pão nosso de cada dia da Seahawk por muito tempo foi exatamente esse trabalho — alto volume, complexidade relativamente baixa, escopo bem definido. Um cliente te entrega um arquivo Figma, você constrói, você faz QA, você lança. Os ciclos de feedback eram curtos. Se algo quebrava, você sabia em poucas horas. Escrever testes para esse contexto é o equivalente do desenvolvedor a laminador um Post-it.
Mas eu generalizei essa lição de forma muito agressiva. Comecei a tratar todos os projetos como sites de brochura. Até os com fluxos de checkout customizados no WooCommerce. Até o dashboard fintech que construímos no início de 2023 para um cliente em Frankfurt — API REST totalmente customizada, autenticação JWT, três níveis diferentes de permissão de usuário. Sem testes. Apenas "QA manual cuidadoso." Isso foi arrogante, e nos custou caro.all projects like brochure sites. Even the ones with custom WooCommerce checkout flows. Even the fintech dashboard we built in early 2023 for a client in Frankfurt — full custom REST API, JWT auth, three different user permission tiers. No tests. Just "careful manual QA." That was arrogant, and it bit us.
O projeto Frankfurt foi lançado com um bug de permissões que permitia usuários de nível editor consultar dados de nível admin sob uma combinação específica de filtros. Não pegamos até o time interno rodar uma revisão de segurança seis semanas após o lançamento. Envergonhador. Corrigível. Mas o tipo de coisa que um teste de integração básico teria sinalizado antes mesmo de abrirmos um pull request.
---
O Que As Ferramentas de IA Para Código Realmente Mudaram
Aqui está a coisa que a maioria das pessoas perde quando fala sobre Copilot ou Cursor ou seja qual for o modelo em alta este mês: o código parece estar certo. Esse é o problema.looks right. That's the problem.
Quando um desenvolvedor junior escreve código bugado, você costuma ver a incerteza nele. Nomes de variáveis estranhos, um comentário que diz // não tenho certeza disso, uma função que é claramente copiada duas vezes. O código telegafa sua própria fragilidade. Código de IA não. É estilisticamente consistente, bem nomeado, e estruturado de um jeito que lê como intencional. A confiança é inteiramente cosmética.// not sure about this, a function that's clearly copy-pasted twice. The code telegraphs its own fragility. AI code doesn't. It's stylistically consistent, well-named, and structured in a way that reads as intentional. The confidence is entirely cosmetic.
Estudos do grupo Human-Computer Interaction de Stanford sinalizaram que desenvolvedores usando assistentes de IA tendem a confiar demais em código gerado na primeira leitura. Isso combina com minha própria experiência. Eu daria uma olhada em uma função de 40 linhas que Copilot tinha escrito, pensaria "sim, é basicamente o que eu teria escrito," e seguia adiante. Às vezes funcionava. Às vezes tinha silenciosamente entendido mal o que eu realmente precisava. have flagged that developers using AI assistants tend to over-trust generated code on first read. That tracks with my own experience. I would glance at a 40-line function Copilot had written, think "yeah, that's basically what I'd have written," and move on. Sometimes it was fine. Sometimes it had silently misunderstood what I actually needed.
O modo de falha específico que eu continuava encontrando: lógica condicional ao redor de casos extremos que a IA não tinha razão para antecipar. Ela escrevia uma função que tratava o caminho feliz perfeitamente e depois falhava silenciosamente em entradas null, arrays vazios, ou formatos de data não-padrão. Coisas que teriam levado trinta segundos para eu pensar se tivesse escrito o código eu mesmo, porque teria estado pensando enquanto digitava.conditional logic around edge cases the AI had no reason to anticipate. It would write a function that handled the happy path perfectly and then quietly fail on null inputs, empty arrays, or non-standard date formats. Things that would have taken me thirty seconds to think about if I'd written the code myself, because I'd have been thinking as I typed.
A Armadilha da Velocidade
Há uma armadilha real de produtividade aqui. A IA te deixa rápido. Rápido parece ser bom. Você começa a fazer deploy mais rápido e começa a revisar menos cuidadosamente porque a velocidade parece ser evidência de qualidade. Não é. Velocidade e correção não são correlacionadas quando você está usando um modelo de linguagem.
Coloquei aproximadamente 40% mais features em um projeto de cliente em setembro passado do que teria conseguido sem assistência de IA. O projeto também teve mais bugs pós-lançamento do que qualquer coisa que tivesse feito deploy em dois anos. Não foram bugs catastróficos. Mas irritantes. Do tipo que desgasta a confiança do cliente.
---
Por Que Testes Funcionam Diferente Agora (Com IA no Fluxo)
Quando voltei para testes, não voltei ao fluxo antigo. Escrever testes primeiro, depois implementação, depois revisão de código assistida por IA — esse é o loop que consolidei agora.
O interessante é que IA é na verdade excelente em escrever testes, de uma forma que nem sempre é excelente em escrever lógica de aplicação. Dê ao Copilot uma assinatura de função bem definida e peça para gerar um test suite e ele vai produzir cobertura de casos extremos que teria levado vinte minutos para escrever manualmente. Ele imagina caminhos infelizes bem quando a tarefa é especificamente "encontre maneiras disso quebrar".AI is actually excellent at writing tests, in a way it isn't always excellent at writing application logic. Give Copilot a well-defined function signature and ask it to generate a test suite and it'll produce edge-case coverage I'd have taken twenty minutes to write manually. It imagines unhappy paths well when the task is specifically "find ways this can break."
Então eu meio que inverti a coisa. Eu escrevo a especificação de testes. IA completa os casos de teste. Depois IA escreve a implementação. Depois eu leio a implementação através da lente desses testes, em vez de apenas ler o código frio.through the lens of those tests, rather than just reading the code cold.
É mais lento do que pure vibe-coding. Mas é mais rápido do que o fluxo antigo de escrever tudo manualmente, incluindo testes. E fez deploy de zero bugs de permissões desde Frankfurt.
As Ferramentas que Estou Realmente Usando
- [Vitest](https://vitest.dev) para qualquer coisa em JavaScript ou TypeScript. Substituiu Jest para mim completamente no ano passado — a configuração é mais sensata e o watch mode é rápido. for anything JavaScript or TypeScript. Replaced Jest for me entirely last year — the config is saner and the watch mode is quick.
- PHPUnit ainda, para WordPress e trabalho PHP customizado. Nada substituiu. still, for WordPress and custom PHP work. Nothing has replaced it.
- O atalho "test this function" do Cursor — genuinamente uma das features individuais mais úteis em qualquer editor que já usei. — genuinely one of the most useful single features in any editor I've used.
- GitHub Actions para CI. Tests rodam a cada push para main. Leva cerca de 90 segundos na maioria dos projetos. for CI. Tests run on every push to
main. Takes about 90 seconds on most projects.
---
O Argumento Contra Tests (Steel-Manned)
Quero dar a essa posição uma oportunidade justa porque a sustentei por quase dois anos.
O argumento real não é "tests são inúteis." É "tests têm um custo e muitos projetos não justificam esse custo." Escrever e manter uma suite de testes leva tempo. Em um projeto com lifespan curto — um microsite de campanha, uma landing page de marketing, um protótipo de hackathon — esse investimento de tempo tem retorno zero. O projeto estará morto antes dos testes salvarem você de algo.
E há um ponto mais sutil: testes ruins são piores que nenhum teste. Uma suite de testes que passa porque os testes são tautológicos (você está essencialmente testando que sua função retorna o que você disse que retorna) te dá falsa confiança. Já vi isso em agências. Desenvolvedores escrevendo testes que sempre passam porque ninguém questionou o que eles realmente estavam verificando.bad tests are worse than no tests. A test suite that passes because the tests are tautological (you're essentially testing that your function returns what you told it to return) gives you false confidence. I've seen this at agencies. Developers writing tests that always pass because nobody challenged what they were actually verifying.
Martin Fowler escreveu bem sobre isso — percentuais de coverage não são uma medida de qualidade de testes. Um número de 90% de coverage pode mascarar uma suite completamente vazia. — coverage percentages are not a measure of test quality. A 90% coverage number can mask a completely hollow suite.
Então: não teste tudo. Não teste porque parece profissional. Teste porque você identificou lógica que é estrutural e seria caro quebrar.
---
O Que Eu Testo Agora (E O Que Não Testo)
Aqui está a decisão real em que cheguei depois dos últimos oito ou nove meses:
Eu testo:
- Qualquer função que lida com dinheiro, permissões ou transformação de dados
- Qualquer endpoint de API que não seja um pass-through CRUD direto
- Lógica de negócio customizada onde o cliente especificou o comportamento exato por escrito
- Qualquer coisa que uma IA escreveu e que eu não li completamente linha por linha
Eu não testo:
- Renderização de UI (Testes de snapshot nunca me salvaram uma vez em nove anos. Nem uma.)
- Wrappers de API de terceiros onde o comportamento externo está fora do meu controle
- Scripts únicos que rodam uma vez e são deletados
- WordPress hooks padrão a menos que estejam fazendo algo incomum
Pronto. Nenhuma grande filosofia. Só uma lista baseada em onde já fui queimado.
---
O Workflow Que Realmente Funciona Para Mim
Como algumas pessoas pediram em comunidades Slack onde estou, aqui está a sequência real:
- Escreva um breve comentário de spec no topo do arquivo — o que este módulo faz, o que não faz, casos extremos que já conheço.
- Peça ao Cursor para gerar casos de teste a partir desse comentário antes de escrever qualquer implementação.
- Revise aqueles casos de teste. Delete os desnecessários. Adicione qualquer um que a IA tenha deixado passar.
- Deixe o Copilot ou Cursor escrever a implementação.
- Execute os testes. Eles vão falhar. Corrija a implementação (não os testes).
- Leia o diff antes de fazer push — código assistido por IA ainda precisa de revisão humana.
O passo 6 é inegociável. Peguei três bugs genuinamente graves nos últimos quatro meses só lendo o diff lentamente antes de fazer push. Nada de genial. Só lendo.
O framing original de TDD de Kent Beck nunca foi sobre 100% de cobertura ou metodologia perfeita. Era sobre construir um loop de feedback rápido o bastante para pegar erros antes que se acumulem. Essa ideia — loops de feedback rápidos — é mais relevante agora do que era em 2003. Porque a IA comete erros mais rápido do que qualquer desenvolvedor que já contratei. was never about 100% coverage or perfect methodology. It was about building a feedback loop fast enough to catch mistakes before they compound. That idea — fast feedback loops — is more relevant now than it was in 2003. Because the AI makes mistakes faster than any developer I've ever hired.
---
FAQ
Isso desacelera sua velocidade de entrega?
Em torno de 10 a 15% em projetos complexos. Em projetos simples, talvez não — a IA gera os testes tão rapidamente que o overhead é mínimo. Para projetos onde um bug custaria dinheiro real para corrigir após o lançamento (e a maioria dos projetos com dinheiro real se enquadra nisso), esses 15% valem cem vezes mais.
E o TypeScript? A tipagem forte não substitui um monte de testes?
Parcialmente. TypeScript pega uma classe inteira de erros em tempo de compilação que você costumava precisar de testes para encontrar. Mas tipos não testam lógica de negócio. Eles não verificam que sua função de cálculo de desconto aplica as regras certas para clientes atacadistas. Isso continua sendo com você.
Desenvolvedores juniores deveriam usar ferramentas de codificação com IA se não estão escrevendo testes?
Não. Opinião forte. Um desenvolvedor junior usando Copilot sem testes está essencialmente pilotando um avião no piloto automático sem entender como o piloto automático funciona ou como pousar manualmente. A IA vai produzir código que parece de nível sênior, o junior não vai saber em quais partes desconfiar, e você vai ter um incidente em produção eventualmente. Testes pelo menos dão a eles um mecanismo para verificar o output que estão aceitando.
Por que você parou de escrever testes em primeiro lugar, honestamente?
Burnout, parcialmente. E um período onde todo projeto era genuinamente simples e testes genuinamente não estavam compensando. O erro foi não notar quando a complexidade do projeto mudou e se ajustar accordingly. Essa é a lição real — não "sempre teste" ou "nunca teste" mas saber em qual categoria um dado projeto se encaixa.
---
Escrever testes não costumava parecer proteção. Parecia burocracia. A IA mudou isso. Não porque a IA é ruim — ela me tornou significativamente mais rápido — mas porque introduziu uma nova classe de erros confiantes, bem-formatados, aparentemente plausíveis que eu não consigo pegar lendo código do jeito que eu costumava. Os testes não são para a IA. São para mim. Uma função coercitiva para pensar sobre o que eu realmente preciso que o código faça antes de aceitar o que o modelo me entrega.
Gostaria de ter enquadrado isso assim dois anos atrás.
