Facebook
31 de agosto de 2026 | adrianosantostreina.com.br/blog Sobre o Autor

O Cão de Guarda do Código: Construindo um Harness de Testes que Não Deixa a IA Passar Batido

Você pediu para o agente implementar uma função de cálculo de frete considerando peso, distância e categoria de produto. O código voltou limpo, bem indentado, com nomes de variáveis sensatos e até um comentário explicando a regra de negócio. Você rodou, testou dois ou três casos na mão, funcionou, fez o merge. Três semanas depois, o suporte reporta que pedidos internacionais com peso fracionado estão gerando frete negativo. Ninguém pegou isso porque ninguém testou esse caminho — nem você, nem a IA, e muito menos um processo automatizado que devesse ter feito isso por você.

Esse é o padrão mais recorrente de falha em times que adotaram geração de código por IA sem adaptar sua estrutura de verificação. O problema não é a IA escrever código ruim — na maioria das vezes ela escreve código sintaticamente correto e estilisticamente aceitável. O problema é que código plausível e código correto são coisas diferentes, e a inspeção visual humana é péssima para distinguir uma coisa da outra em volume. Você precisa de um harness: uma estrutura de testes desenhada especificamente para capturar as classes de erro que agentes de IA cometem com mais frequência, rodando de forma automática, antes que o código saia do seu ambiente local.

O que é, de fato, um harness de testes para código de IA

O termo “harness” já existe há décadas em engenharia de software — é a estrutura que prepara o ambiente, executa o código sob teste e verifica os resultados. O que mudou com a geração de código por agentes é o propósito desse harness: ele deixa de ser apenas “os testes do projeto” e passa a ser uma camada de contenção específica contra os modos de falha característicos da IA.

Esse conceito tem sido tratado com mais profundidade recentemente sob o nome de Harness Engineering, que trata não apenas dos testes de comportamento, mas de restrições estruturais sobre o próprio código-fonte gerado — como limites de tamanho de arquivo, complexidade ciclomática e padrões arquiteturais que o agente não pode violar silenciosamente.

💡 Dica do Mestre: O artigo da NxCode sobre Harness Engineering define bem essa disciplina como “projetar ambientes, restrições e loops de feedback que tornam os agentes de codificação de IA produtivos e seguros”. Vale a leitura para entender o pano de fundo teórico antes de partir para a implementação.

Na prática, um harness de testes para código gerado por IA precisa cobrir três camadas que se complementam, não que se substituem:

  • Testes estruturais: verificam se o código respeita as convenções e limites do projeto (tamanho de função, complexidade, imports não usados, padrões de nomenclatura).
  • Testes comportamentais: os testes unitários e de integração tradicionais, mas escritos — ou pelo menos revisados — de forma independente do código que estão validando.
  • Testes de propriedade e casos-limite: a camada que mais falta nos projetos comuns, e a que mais pega os erros característicos de IA: valores negativos, nulos, vazios, extremos, concorrência.

Por que os testes “óbvios” não bastam

Um agente de IA, ao gerar tanto a implementação quanto os testes para ela (algo comum quando você pede “implemente X com testes”), tende a criar testes que confirmam o comportamento que ele mesmo implementou, não que o desafiam. Isso é viés de confirmação estrutural: o modelo não vai gerar um teste que exponha uma falha na lógica que ele acabou de escrever, porque ele não “sabe” que a lógica está errada — ele só sabe que parece coerente com o que foi pedido.

Esse é o motivo pelo qual pedir “gere os testes também” no mesmo prompt da implementação é uma prática arriscada quando usada isoladamente. O harness precisa vir de uma fonte separada — idealmente escrita por você a partir da especificação, não a partir do código gerado.

💡 Dica do Mestre: O material da Kimi AI sobre fluxos de trabalho confiáveis com IA reforça exatamente esse ponto: separar planejamento de execução para que cada alteração seja fácil de verificar de forma independente de quem (ou o que) a produziu.

Passo a passo: construindo o harness na prática

1. Escreva a especificação de comportamento antes do código

Isso não significa burocracia — significa uma lista objetiva de invariantes que o código precisa respeitar, independentemente de como for implementado. Para o exemplo do cálculo de frete:

Essas invariantes viram a espinha dorsal do seu harness. Note que nenhuma delas depende de como o agente vai implementar a função — elas descrevem o contrato, não a solução.

2. Transforme invariantes em testes de propriedade

Testes de propriedade (property-based testing) são a ferramenta mais subutilizada contra código gerado por IA, porque testam a invariante contra centenas de valores gerados automaticamente, em vez de dois ou três casos fixos. Em Python, com Hypothesis:

Se você trabalha em JavaScript/TypeScript, o equivalente direto é fast-check. Em Java, jqwik. Em Delphi, embora o ecossistema de property-based testing seja mais limitado, você consegue simular o padrão com geração de dados aleatórios dentro do próprio DUnitX, iterando sobre um range de valores em vez de casos fixos — a lógica da técnica não depende da linguagem.

3. Adicione testes de mutação para validar o harness em si

Uma armadilha comum: você escreve os testes, eles passam, você acha que está protegido — mas os testes são fracos e passariam mesmo com a implementação quebrada. Testes de mutação resolvem isso introduzindo pequenas alterações no código (trocar > por >=, inverter uma condição) e verificando se algum teste falha. Se nenhum teste falhar diante da mutação, seu harness tem um buraco.

Para JavaScript/TypeScript, use Stryker Mutator. Rodar mutação em todo commit é caro computacionalmente, então a prática comum é rodar apenas nos arquivos alterados por um PR, e reservar a suíte completa para execuções noturnas ou semanais.

4. Trave limites estruturais no próprio código

Além do comportamento, o harness precisa impedir que o agente produza estrutura problemática mesmo quando o comportamento está correto — funções gigantes, complexidade excessiva, duplicação. Isso é o que o material da AWS Builder chama de testes sobre o código-fonte em si, separados dos testes comportamentais.

💡 Dica do Mestre: O artigo da AWS Builder sobre construção de software com humanos direcionando e IA executando traz exemplos concretos desses limites estruturais, incluindo tamanho máximo de arquivo — uma restrição simples que evita que o agente “resolva” um problema complexo empilhando lógica em uma única função monolítica.

Um exemplo prático com ESLint em um projeto Node.js, forçando limites de complexidade que o agente é obrigado a respeitar:

Em Python, o equivalente é configurar Radon ou Ruff com regras de complexidade McCabe dentro do pipeline de CI, falhando o build quando o limiar é ultrapassado. O ponto central é que essas regras não são sugestões de estilo — são gates que bloqueiam merge, exatamente como um teste que falha.

5. Monte o pipeline de gates em camadas

Um harness eficaz não roda tudo de uma vez sem ordem — ele falha rápido nas verificações baratas antes de gastar tempo nas caras. Um pipeline típico de CI (GitHub Actions, por exemplo) para código com forte presença de IA na geração:

Note a condição no gate de mutação: ele só roda quando o PR altera menos de 15 arquivos, justamente para manter o pipeline rápido em mudanças pequenas — que são exatamente o tipo de contribuição mais comum quando você trabalha com agentes de forma iterativa.

6. Adicione um subagente revisor como camada extra, não como substituto

Uma prática que tem ganhado espaço é usar um segundo agente — com um prompt e contexto diferentes do que gerou o código — para revisar o PR antes da fusão, procurando especificamente por padrões de risco: tratamento de erro ausente, valores mágicos, ausência de testes para caminhos de exceção.

💡 Dica do Mestre: O artigo de Samuel Faj sobre harness de agentes de código para PRs confiáveis cita que a maioria dos desenvolvedores já aponta revisão, edição e teste de código com IA como o principal gargalo do fluxo — e propõe um harness com gates, MCP e subagentes especializados para atacar exatamente esse ponto. É leitura obrigatória se você quer ir além do que este artigo cobre e configurar múltiplos agentes cooperando no processo de verificação.

O ponto importante aqui: o subagente revisor é uma camada de triagem, não de aprovação final. Ele reduz o volume de coisas óbvias que chegam até você, mas a decisão de merge continua sendo humana — sob risco de você recriar o mesmo problema de viés de confirmação, agora entre dois modelos em vez de um.

Erros comuns ao montar esse harness

  • Cobertura de linha como métrica de sucesso: 100% de cobertura não significa nada se os testes não verificam as invariantes certas. Prefira medir cobertura de branches e, melhor ainda, score de mutação.
  • Testes gerados e revisados pela mesma sessão de IA: quebra o isolamento que dá valor ao harness. Gere os testes a partir da especificação em uma sessão separada, ou escreva-os você mesmo para os casos críticos.
  • Ignorar concorrência e estado compartilhado: agentes de IA frequentemente geram código correto em cenário single-thread mas com condições de corrida sutis quando múltiplas chamadas concorrentes acontecem. Se seu domínio tem esse risco, inclua testes de carga concorrente no harness.
  • Gates lentos demais para o dia a dia: se o pipeline leva 20 minutos para rodar, os desenvolvedores vão contornar. Priorize velocidade nos gates que rodam a cada commit e reserve as verificações pesadas para execuções agendadas.

Aprofunde a discussão com quem já está aplicando isso

Um harness bem desenhado é resultado de tentativa e erro dentro do contexto específico do seu projeto — não existe configuração universal que sirva para todo domínio. Trocar experiências com quem já enfrentou esses mesmos problemas em produção acelera muito esse processo de calibração.

Na Comunidade Dev’s AI discutimos justamente esse tipo de configuração prática: quais gates fazem sentido para cada stack, como calibrar testes de mutação sem travar o pipeline, e como montar fluxos de subagentes revisores sem duplicar esforço. Se você está estruturando o harness do seu time agora, vale entrar e comparar notas com quem já passou pelas mesmas armadilhas.

Conclusão

Código gerado por IA não é menos confiável por natureza — ele é confiável na mesma proporção da estrutura de verificação que você constrói ao redor dele. A diferença entre um time que ganha velocidade real com IA e um time que só troca bugs manuais por bugs automatizados está exatamente nesse harness: uma camada de testes estruturais, comportamentais e de propriedade que roda antes que qualquer código, gerado por humano ou por agente, chegue perto de produção.

Comece pequeno — escolha um módulo crítico do seu projeto atual, escreva a especificação de invariantes antes de tocar no código, e monte os três primeiros testes de propriedade. A disciplina se paga rápido, principalmente no dia em que um agente tentar “resolver” um caso de borda inventando um comportamento que ninguém pediu.

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *