Ferramenta da Meta para melhorar testes unitários automatizados: TestGen-LLM
- A ferramenta TestGen-LLM, desenvolvida pela Meta, usa modelos de linguagem de larga escala (LLMs) para melhorar automaticamente testes existentes escritos por humanos.
- As classes de teste geradas pelo TestGen-LLM passaram com sucesso por uma série de filtros que garantem melhorias mensuráveis em relação à suíte de testes original, resolvendo o problema de alucinação de LLM.
- O texto descreve a implantação do TestGen-LLM em test-a-thons de teste para as plataformas Instagram e Facebook da Meta.
Avaliação de desempenho do TestGen-LLM
- Na avaliação para os produtos Reels e Stories do Instagram, 75% dos casos de teste do TestGen-LLM foram compilados corretamente, 57% passaram com confiabilidade e 25% aumentaram a cobertura.
- Nos test-a-thons de teste do Instagram e Facebook da Meta, o TestGen-LLM melhorou 11,5% de todas as classes aplicadas, e os engenheiros de software da Meta aceitaram 73% das recomendações para implantação em produção.
- Este é o primeiro relatório sobre a implantação em escala industrial de código gerado por LLM com essas garantias de melhoria de código.
Opinião da GN⁺
- O TestGen-LLM é uma ferramenta que pode trazer inovação para a automação e a melhoria da qualidade de testes de software, tendo sucesso ao melhorar testes existentes com modelos de linguagem de larga escala.
- A ferramenta contribui significativamente para a comunidade de engenharia de software ao aumentar a cobertura de testes e gerar casos de teste confiáveis em cenários de produção reais.
- A adoção bem-sucedida no test-a-thon da Meta mostra que o TestGen-LLM tem potencial para ser integrado ao desenvolvimento de produtos reais, representando um avanço importante para melhorar a eficiência e a estabilidade do desenvolvimento de software.
1 comentários
Comentários do Hacker News
Em uma grande seguradora onde trabalhei no passado, a diretoria definiu como meta 80% de cobertura de testes para toda a base de código, e as pessoas começaram a escrever testes unitários inúteis para getters/setters de DTOs em Java só para bater a meta
Obviamente os desenvolvedores também não podiam mudar as regras de medição de cobertura do Sonar, e foi aí que aprendi, ainda no início da carreira, que olhar só para KPI pode induzir comportamentos que não têm nada a ver com a intenção original
É bem possível que alguns cenários de teste E2E bem projetados tivessem sido melhores para a qualidade do software
O problema era que o código legado bagunçado estava muito bem testado, com 95% de cobertura. O código novo tinha 100% de cobertura, mas como ficou muito menor, a cobertura total acabou caindo e ele não pôde ser aprovado
Como o que restava era só código de UI em Swing, difícil de testar e com pouco valor em testar, o líder de desenvolvimento, em vez de passar 1 ou 2 semanas escrevendo testes de Swing, deixou o código antigo em algum lugar do repositório e fez os testes apontarem para ele
No fim, milhares de linhas de código morto, que nunca seriam chamadas em produção, ficaram no repositório só para satisfazer o Sonar
O resultado foi o surgimento de milhares de constantes em headers como
static const unsigned ONE = 1;,TWO = 2;,THREE = 3;https://en.m.wikipedia.org/wiki/Mutation_testing
Existem ferramentas e frameworks para praticamente todas as linguagens, como stryker-mutator (C#, TypeScript), pitest (Java) e mutatest (Python)
Em 6 anos de carreira, foi a pior aplicação já escrita que vi, e não era só questão de estilo: havia muitas partes realmente completamente quebradas, mas ninguém sabia o que estava errado
Eu realmente odeio o Sonar. Ele deveria ser usado só para reportar vulnerabilidades; não deveria mandar você renomear variáveis nem dizer “você precisa refatorar esta duplicação de código”. Já existe um backlog de tickets no Jira; eu não queria que ele também dissesse o que fazer e quando fazer
Mas os gestores adoram esse tipo de ferramenta de jogo de poder
O grande problema é tornarem isso obrigatório e depois fazerem você passar por um enorme processo burocrático para evitar absurdos. Na semana passada mesmo, briguei com uma ferramenta obrigatória de qualidade de código porque ela reclamava que
res.status(200).json()não tinha cabeçalho HSTSEla continuava reclamando tanto com configuração manual quanto com
app.use(helmet()), e no fim parecia querer que todo o backend fosse escrito em um único arquivo. Enquanto isso, o HSTS na verdade é tratado de forma mais elegante e automática no ingress ou no load balancerEu até poderia gastar 1 ou 2 semanas marcando isso como falso positivo e explicando para a gerência sênior o que é HSTS para conseguir aprovação, mas no fim acabei adicionando
res.sendJson(data, status = 200)ao protótipo do objeto de resposta. É claramente uma implementação idiota, mas me fez perceber como, em setores muito burocráticos, software ruim é feito pela soma dessas implementações ruinsAo ver a afirmação de que “75% dos casos de teste do TestGen-LLM compilaram corretamente, 57% passaram de forma estável e 25% aumentaram a cobertura”, o problema parece ser que testes gerados por LLM têm alta chance de “certificar” um comportamento com bug.
Isso parece ainda mais provável em codebases que já têm baixa cobertura de testes. Quando uma pessoa escreve um teste novo manualmente, há a vantagem de existir alguém para julgar se o sistema é burro ou se o teste está errado.
No mínimo, esses testes deveriam ficar separados em uma pasta especial de testes e ser tratados com o nível adequado de desconfiança
Ainda assim, uma codebase com boa cobertura permite fazer refatorações grandes com segurança, sem regressões, e isso continua sendo uma propriedade útil mesmo se houver bugs e a refatoração os preservar.
O risco de uma ferramenta de geração de testes projetada para codificar o comportamento atual é cair em uma falsa sensação de segurança, quando na prática ela só codificou o comportamento atual.
Talvez isso pudesse ser resolvido se não chamássemos isso de “teste”, mas de algo como “snapshot de comportamento”. O nome deveria transmitir que captura o comportamento atual, não o comportamento correto
Por isso, acho que sempre é necessário algum nível de supervisão humana para determinar qual cenário aconteceu.
Isso acontece em todo tipo de sistema, e as pessoas tendem a achar que o problema se resolve acrescentando mais uma camada de automação, como aqui. Os testes foram inventados para verificar se o programa original funciona corretamente; se automatizamos isso também, reencontramos o mesmo problema em um código maior, ou seja, na forma de testes em vez de assertions
Às vezes você não sabe como criar factories para as entradas auxiliares necessárias aos testes, mas sabe como o código em si deveria funcionar.
Se o LLM montar a estrutura inicial dos testes e facilitar para o desenvolvedor escrever a validação da lógica de negócio, isso pode ser um grande ganho.
Porém, se os testes gerados ficarem acoplados demais à implementação, como acontece com a maioria dos testes unitários, eles vão desacelerar o desenvolvimento. Se for difícil demais corrigir testes individuais, pode até acontecer de as pessoas apagarem todos os testes em mudanças grandes e os gerarem novamente
Parte do código pode depender desse bug e, corrigi-lo por acidente ou de propósito, pode causar um problema mais sério.
Claro, esse tipo de teste não pode substituir testes que verificam os requisitos reais
Mas existem incontáveis sistemas legados em modo de manutenção com baixa cobertura, e nesses casos gerar testes que validem o comportamento atual é muito útil. Isso permite verificar se, quando alguém faz uma mudança, o restante continua igual
Lendo o PDF, isso parece gerar testes que “apenas” passam repetidamente, isto é, que não são instáveis.
O objetivo principal é criar um conjunto de testes de regressão com testes que fixem o comportamento do código existente, não substituir testes escritos por desenvolvedores que conhecem os requisitos funcionais.
Quase 20 anos atrás, numa empresa onde trabalhei, também testamos o AgitarOne, com a promessa de gerar automaticamente casos de teste que explorassem o comportamento de código Java. Ele também conseguia criar testes que passavam quase automaticamente para serem usados como conjunto de regressão.
Pessoalmente, eu não gostei. Surgia coisa demais, e a gerência entendia que, se a cobertura subia, a qualidade também subia. Fico curioso para saber o quanto essa abordagem com LLM do FB é melhor do que aquilo naquela época.
http://www.agitar.com/solutions/products/agitarone.html
Até que um LLM consiga julgar a correção real sem depender da suposição de que bons testes passam, ou sem depender de um oráculo, parece difícil ir além disso. De algum modo, o prompt teria que incluir expectativas sobre o comportamento
O valor do teste está em garantir que não se quebre algo com que alguém se importa, não em congelar para sempre todo comportamento de edge case pouco usado que é apenas um subproduto de uma implementação específica
Pela minha experiência, escrever testes costuma ser uma excelente forma de avaliar a qualidade do código.
Se os testes são complexos ou é difícil atingir cobertura, há grande chance de que o código testado precise ser melhorado
Código com baixo acoplamento, alta coesão e baixa complexidade deveria ser fácil de testar unitariamente
Dizem que, na avaliação dos produtos Reels e Stories do Instagram, 75% dos casos de teste do TestGen-LLM compilaram corretamente, 57% passaram de forma estável e 25% aumentaram a cobertura.
Nos eventos de testes do Instagram e do Facebook da Meta, houve melhoria em 11,5% de todas as classes aplicadas, e 73% das recomendações foram aprovadas por engenheiros de software da Meta para deployment em produção.
Não sei se isso é uma boa proporção. Eu precisaria ler mais para saber se o que foi rejeitado eram erros pequenos que pegaríamos em code review ou problemas graves. Se fosse um engenheiro humano com taxa de falha de 25%, talvez não ajudasse muito, dependendo do tipo de falha.
Também fico em dúvida se toda a missão de automatizar a geração de testes unitários para código Android é uma boa direção. O pessoal do TDD provavelmente estaria se revirando no túmulo — ou na cama de casa. Ainda assim, imagino que acrescentariam alguma ressalva no fim
no unlogged.io, por um tempo o foco principal foi a geração automática de testes JUnit, mas isso não decolou por alguns motivos
Havia testes demais sendo gerados, os desenvolvedores não queriam fazer a manutenção, eles não conseguiam simular cenários reais, e cobertura de código era uma métrica de vaidade. Os desenvolvedores encontravam jeitos de contornar a meta com cenários sem sentido
Agora estamos trabalhando para simular todos os cenários únicos de produção e oferecer testes de replay no-code que os desenvolvedores possam reproduzir localmente com as dependências externas mockadas
Aliás, sou fundador do unlogged.io
Quero ir na direção oposta. Você fornece os critérios de aceitação, ele gera testes para verificá-los, e depois gera o código que passa nesses testes
Às vezes dá para fazer algo parecido de forma limitada com o Copilot, mas não sei por que parece que ninguém está focando nessa ordem
O TestGen-LLM é um artefato realmente estranho. Parece que pode servir como primeira etapa de uma refatoração ou reescrita, mas o destaque dado à cobertura de código no artigo passa uma sensação de total falta de critério
Talvez seja útil se a organização já estiver quebrada por exigir cobertura alta, mas o TestGen-LLM não vai melhorar o código do projeto de forma alguma e só vai aumentar o atrito para implementar melhorias reais
Seria muito mais útil gerar testes para casos de borda que podem passar ou não, mas o TestGen-LLM depende de erros de compilação e testes que falham para filtrar o lixo gerado por LLM
O fato de o artigo não mostrar nenhum exemplo dos testes gerados me faz suspeitar que eles sejam amadores, como outros códigos gerados por LLM que vi até agora
Isso até ajudou a entender o que o código estava tentando fazer
É interessante que isso seja um artigo de 12 páginas escrito por funcionários da Meta para promover IA para desenvolvedores, e eles até trouxeram um diagrama de Sankey
Posso estar errado, mas se vão apresentar desse jeito, não deveriam fornecer também informações reproduzíveis?
Não é teoria da conspiração, só que eu não tenho um volume de dados no nível do que a Meta usa para treinamento. Fico curioso se eles chegaram a divulgar algo
Fico me perguntando qual será o custo de manter, no futuro, um enorme corpus de testes gerados automaticamente
Não basta só gerar casos de teste; também é preciso oferecer métodos automatizados para atualizá-los