O novo gerador de testes baseado em LLM da Meta
(read.engineerscodex.com)O novo gerador de testes baseado em LLM da Meta oferece uma visão do futuro do desenvolvimento
- A Meta publicou o artigo "Automated Unit Test Improvement using Large Language Models at Meta".
- O artigo mostra como usar IA para acelerar o desenvolvimento e reduzir bugs de software.
- Ao integrar LLMs ao fluxo de trabalho dos desenvolvedores, ele propõe melhorias de software precisas e completas para aprimorar a cobertura de código atual.
Pontos principais
- O TestGen-LLM usa a abordagem 'Assured LLM-based Software Engineering' (Assured LLMSE).
- Ele usa uma abordagem de ensemble que gera melhorias de código com vários LLMs, prompts e hiperparâmetros, e seleciona a melhor melhoria.
- O TestGen-LLM foi projetado especificamente para melhorar testes já escritos por humanos.
Estatísticas
- Na avaliação dos produtos Reels e Stories do Instagram, 75% dos casos de teste gerados pelo TestGen-LLM compilaram com sucesso, 57% passaram de forma confiável e 25% aumentaram a cobertura.
- O TestGen-LLM conseguiu melhorar 10% de todas as classes às quais foi aplicado, e os desenvolvedores aceitaram 73% das melhorias de teste e as colocaram em produção.
- Em um "test-a-thon" em que engenheiros da Meta geraram testes para aumentar a cobertura de testes do Instagram, a mediana das linhas de código adicionadas pelos testes do TestGen-LLM foi de 2,5.
Insights práticos
- Este é um bom exemplo de como LLMs podem ser usados para melhorar com eficiência a produtividade de desenvolvimento e a confiabilidade de software.
- O verdadeiro valor dos LLMs está em encontrar e capturar edge cases inesperados.
- Para usar LLMs em produção, são necessários orquestração, pipelines e processamento.
Como o TestGen-LLM funciona
- O TestGen-LLM aplica uma série de filtros semânticos às soluções candidatas geradas pelo LLM interno da Meta para preservar apenas os testes de maior valor.
- Filtro 1: capacidade de compilação, Filtro 2: execução (se o teste passa), Filtro 3: instabilidade, Filtro 4: melhoria de cobertura.
- Esses filtros de processamento garantem a melhoria da suíte de testes.
Conclusão
- Este artigo é uma boa forma de acompanhar os avanços dos LLMs na área de confiabilidade de software, algo para o qual muitos desenvolvedores já usam LLMs.
- Os LLMs serão cada vez mais capazes de encontrar bugs e testar sistemas de software cada vez mais complexos.
Opinião do GN⁺
- Este artigo oferece insights interessantes sobre como a inteligência artificial pode impactar o futuro do desenvolvimento de software.
- Ferramentas como o TestGen-LLM podem ser de grande ajuda para automatizar o trabalho dos desenvolvedores e aumentar a eficiência.
- O avanço dessas tecnologias está seguindo na direção de reduzir a complexidade do desenvolvimento de software, melhorar a qualidade e economizar tempo dos desenvolvedores.
1 comentários
Opiniões do Hacker News
É interessante a tendência de querer usar LLMs primeiro para escrever código de teste, antes de implementação
Talvez por eu ter feito TDD demais, vejo testes como algo que descreve como o sistema deve se comportar, e essa parte deveria ser definida por pessoas. O código deve se ajustar dentro dos guardrails criados pelos testes
Dito isso, LLMs podem ajudar a apontar áreas em que a especificação está insuficiente. Talvez o que esteja acontecendo aqui seja fazê-los sugerir testes unitários para partes menos especificadas
Mesmo antes dos LLMs, às vezes eu pensava se, caso todos os testes estivessem escritos, um macaco com uma máquina de escrever não conseguiria criar a aplicação
São testes que definem não como uma pessoa acredita que o código deveria se comportar, mas como a base de código atual realmente se comporta
Isso permite reescrever, refatorar e redesenhar minimizando regressões. O problema de muito código legado é que ninguém entende o comportamento pretendido e, às vezes, até os usuários acreditam que ele deveria se comportar de um jeito diferente do comportamento real
Por isso, a coisa mais importante é não mudar o comportamento, a menos que seja uma mudança explicitamente desejada
A ideia básica é expressar proposições mais fracas sobre o comportamento do código como “propriedades”, em vez de um sistema de prova completo em forma fechada, e verificá-las dentro de limites essencialmente probabilísticos
O exemplo clássico é inverter strings. Se você inverter uma string duas vezes, em geral deveria obter a entrada original. Com uma linha de código, dá para verificar tantos casos extremos estranhos de Unicode quanto o tempo e a eletricidade permitirem
O exemplo parece trivial, mas vi especialistas em CUDA que trabalhavam com diferenciação automática e kernels — no que virou o PyTorch — usarem essa abordagem de forma extremamente eficaz, conseguindo algo como 5 vezes mais confiança no código com metade do esforço e do custo
Nem sempre encaixa bem, mas quando encaixa é excelente, e LLMs parecem conseguir chegar bem perto de exemplos de Hypothesis em vez de começar do zero
Por outro lado, ao escrever testes, você precisa descrever o que a aplicação deve fazer em uma linguagem extremamente verbosa e cheia de restrições, além de escrever dezenas ou centenas de linhas de código de configuração só para inserir alguns if/else glorificados
Em linguagens como C++ ou Java, testes unitários são feitos de tédio, então não é nada surpreendente surgir o instinto de delegar esse trabalho a um LLM
Já vi muitos engenheiros passarem dias codando e depois, por obrigação, escreverem alguns testes para “provar” que o sistema funciona. A cobertura é baixa e geralmente frágil
Para engenheiros que pensam e trabalham assim, um sistema desses pareceria um presente dos céus
Já tive um gerente que proibiu escrever testes primeiro porque dizia que era lento. Felizmente eu estava alocado como consultor e pude ignorá-lo dizendo “fale com meu chefe”, mas ele provavelmente pensava como os engenheiros acima
Visto de outro jeito, a maioria dos desenvolvedores odeia documentação. Eles adorariam uma IA que escrevesse ótima documentação a partir do código. E, para esses desenvolvedores, ótima documentação é documentação que eles não precisam escrever
Código de teste muitas vezes é tratado como código de baixa prioridade e entregue a engenheiros mais juniores, o que parece exatamente o oposto do desejável
Não quero revisar tudo, mas uma parte parece especialmente equivocada
Li o artigo original por alto logo depois que saiu e agora estou apenas passando os olhos, então parto do pressuposto de que minha memória está meio nebulosa
O blog escreveu que a maioria dos testes do TestGen-LLM da Meta cobriu apenas mais 2,5 linhas, mas que um teste cobriu 1326 linhas, e que o valor desse único teste era “exponencialmente maior”, além de dizer que havia grande valor no LLM pensar ativamente fora da caixa para capturar casos de borda inesperados
Mas a expressão “exponencialmente mais valioso” por si só já deveria acionar o detector de bobagem. Ao olhar o paper, os autores descrevem essa cobertura de 1326 linhas como um único teste que acertou o jackpot, e dizem que a cobertura adicional realista esperada por um teste individual do TestGen-LLM tem mediana de 2,5 linhas
Os autores não mencionam “casos de borda inesperados” nem “pensar fora da caixa”. Pelo contrário, apresentam isso como um caso excepcional que pode ter tocado um ramo de um switch horrível, ou simplesmente ser uma coincidência da forma como a cobertura de código é calculada
Também chama atenção que eles não aprofundem isso na seção de “resultados qualitativos”. Uma explicação imprecisa não ajuda ninguém. A internet já tem gente demais fingindo entender o que apenas fingiu ter lido
Editei o texto para deixar mais claro que algumas interpretações são minha opinião
O texto é mais um comentário sobre o que os resultados do paper significam do que um resumo do paper. De todo modo, o Hacker News é um lugar para discussão
Ainda assim, continuo achando correta a parte de “exponencialmente mais valioso”. O ponto central do valor é justamente que um LLM pode, por acaso, “acertar o jackpot” em termos de cobertura de testes
Se ele continuar tentando várias combinações e acertar um único jackpot como no paper, isso é muito valioso para a equipe. Pode ser um teste que não era óbvio para uma pessoa escrever manualmente, ou que era tedioso demais
Como alguém que, em bases de código de Big Tech (F/G), já sabia o que precisava ser testado, mas gastou tempo demais tentando descobrir “como testar”, vejo muito valor nisso
Está claro que essa equipe também está sendo empurrada para métricas centradas em número de linhas de código e quantidade de diffs. No fim, isso será apenas mais uma ferramenta de geração de código que cria uma montanha de código difícil de depurar
Bons testes são difíceis, e cobertura não é necessariamente algo bom
É fácil escrever testes demais, engessar o programa e, na prática, criar um programa de detecção de mudanças. Vira algo como: “Você mudou alguma coisa, todos os testes quebraram. Tudo bem, agora é só pedir para o LLM gerar de novo! 100% de cobertura! Incrível! Progresso!”
Para mim, é uma oportunidade de confirmar se aquela mudança foi intencional. Sem isso, como saber se o programa está fazendo o que deveria fazer?
Fora isso, é preciso ler os bons testes em que outras cinco pessoas pensaram. Todos nós escrevemos testes mal, cada um à sua maneira
Depois disso, em toda mudança, o desenvolvedor naturalmente apertava o botão de regenerar e commitava tudo. O diff era rico, mas o sinal era duvidoso
Depois de trabalhar na indústria de semicondutores, especialmente em litografia computacional, onde design orientado a testes é padrão, acho isso difícil de aceitar
Não quero dizer que testes devam sempre ser escritos antes do código de produção. Mas testes são parte do código tanto quanto qualquer outra parte do codebase, e precisam ser escritos junto com o código que testam
A parte mais importante dos testes é mostrar a intenção do desenvolvedor. A suíte de testes mostra como o código deve ser usado, o que ele faz, o que não faz e para que foi escrito
Assim, quando outro desenvolvedor usar ou modificar esse código, não precisa sair procurando pistas pelo codebase como Sherlock Holmes
Se os testes não contam uma história, você está escrevendo testes do jeito errado
Até que computadores consigam ler mentes e entender melhor a intenção, geradores baseados em IA/LLM não conseguem fazer esse trabalho no nosso lugar
Claro, se o único objetivo da suíte de testes for ganhar um check verde na verificação pré-commit e mostrar números bonitos de cobertura, dá para dobrar a produtividade com IA
Geradores automáticos de código vão ajudar a escrever mais código ruim na velocidade da luz. Se alguém reclamar que o código está inchado e difícil de entender por causa de muito boilerplate, é só dizer para resolver com IA. Funcionou para você
Esse realmente parece ser o futuro do desenvolvimento, mas não é o futuro que eu espero
O que você descreveu parece testar o “núcleo” do código. São testes que também servem em parte como documentação, validação e estabilidade
Outros testes, como fuzzing, entregam um valor completamente diferente. Vejo testes baseados em IA ocupando um espaço voltado para a cauda da distribuição: muitos testes de menor valor que ficam abandonados porque faltam energia e tempo humanos
Também vejo o estado atual das ferramentas de IA assim: ferramentas de apoio cognitivo
Eu ficaria até surpreso se essa linha de pesquisa não desse frutos consideráveis nos próximos anos
Estou citando de novo, com pequenas revisões, algo que escrevi quando o próprio artigo foi publicado. O texto deles apresenta as estatísticas de forma incorreta
https://news.ycombinator.com/item?id=39406726
O resumo não corresponde ao conteúdo real do artigo. Ele faz parecer que os números são proporções por caso de teste, como “75% compilaram corretamente, 57% passaram de forma estável, 25% aumentaram a cobertura”
O relatório real fala em termos de classes de teste, e cada classe contém um ou mais casos de teste
O sentido é: “75% das classes de teste tinham pelo menos um novo caso de teste que compilava corretamente”, “57% das classes de teste tinham pelo menos um caso de teste que compilava corretamente e passava de forma estável”, “25% das classes de teste tinham pelo menos um caso de teste que compilava, passava e aumentava a cobertura de linhas em comparação com outras classes de teste do mesmo alvo de build”
São frases completamente diferentes. Há até uma nota de rodapé dizendo que, como cada tentativa de expandir uma classe de teste pode envolver várias tentativas de geração de casos de teste, a taxa de sucesso por caso de teste geralmente é muito menor do que a taxa por classe de teste
Mesmo assim, na conclusão eles voltam a apresentar os resultados de forma incorreta, como no resumo. Escrevem que, usando o TestGen-LLM em modo experimental, a taxa de sucesso por caso de teste foi de 25%, e que, ao relaxar a exigência de cobertura de linhas e exigir apenas build e aprovação, a taxa de sucesso sobe para 57%
Tenho empatia por quem vai ter que manter esse péssimo código legado de LLM no futuro
Vai ser feio
Talvez até pareça bem parecido, com comentários e documentação mais completos, e talvez menos propenso a estar ativamente errado
LLMs nunca vão ficar melhores do que são agora e não evoluíram nada nos últimos 2 anos. São apenas cadeias de Markov chamativas
Só dá para usá-los para escrever código quando alguém que não sabe programar commita código cegamente em produção sem nenhuma revisão
Para quem sabe programar, não têm como ser úteis e não aumentam produtividade
Vou ignorar essa baboseira de LLM que não muda absolutamente nada no mundo, e você certamente deveria fazer o mesmo
Se não for bem separado, vira facilmente um ambiente hostil aos desenvolvedores, com gerentes ignorantes exigindo alta cobertura e juniors entusiasmados inserindo escondido grandes volumes de testes por IA
No fim, toda vez que você envia um trabalho, acaba tendo que receber o carimbo de aprovação de código de teste gerado por LLM que é difícil de manter
Escrever alguns testes pode ficar mais rápido, mas não há garantia de que a manutenção ficará mais rápida. O mesmo vale para a manutenção do código sendo testado, porque não há garantia de que bons testes serão gerados
O processo trabalhoso de escrever testes normalmente também ajuda o desenvolvedor a verificar o design logo no início. Se é difícil de testar, geralmente não é um bom design; por exemplo, no contexto de escrever código junto com outras pessoas, muitas vezes o contrato do componente não está suficientemente abstraído
Um ponto fácil de ignorar é que testes são código sacrificável. A maioria nunca vai capturar nada durante toda a vida, e isso é OK. Eles dão tranquilidade automatizada e, em caso de falha, reduzem as pistas falsas
Mas investir ao máximo em uma salvaguarda probabilística nem sempre traz retorno. Quanto mais a cobertura se aproxima do topo, menor é a utilidade marginal. A menos que sejam caminhos de execução de muito tráfego, como em uma biblioteca padrão, ostentar cobertura alta geralmente não é recompensado
Além disso, quase sempre é preciso haver um ecossistema de testes — não só testes unitários, mas testes de integração, testes de sistema etc. — para o conjunto funcionar. Será que um LLM vai sentar na reunião de design, entender a arquitetura e escrever esses testes também? Ou vai exagerar o que consegue fazer e empurrar para fora o que deveria ser feito?
Ao investir esforço em testes, é preciso ter o senso de julgar “o que é relevante” não só no momento da escrita, mas também no momento do design e da manutenção. Humanos fazem isso muito bem; ferramentas de IA, não
A parte em que um LLM pode economizar tempo são as teclas digitadas por um desenvolvedor experiente que já tem noção do que vale a pena testar e do que não vale. Ao mesmo tempo, ele também pode atrapalhar, fazendo coisas pouco relevantes entrarem sorrateiramente no código — e isso já vem acontecendo
Não queremos uma economia que produza teclas digitadas. Queremos um conjunto de entradas bem pensadas e altamente relevantes. E esperamos que esta última seja bem separada da primeira, para que com o tempo a utilidade objetiva — ou a falta dela — fique evidente
Já fiz isso com o GPT-4
Mostrei um módulo TypeScript e pedi para gerar testes unitários; ele criou testes funcionais que cobriam não só o caminho feliz, mas também alguns casos de borda
O ChatGPT supera as expectativas em vários aspectos. Testes parecem ser algo fácil para o nível de capacidade do GPT
Na semana passada, pedi que escrevesse código Python que percorresse uma AST e criasse um grafo e componentes no React Flow. Não fiz correções; apenas repeti algumas rodadas de feedback no prompt, e funcionou muito bem. Já vi muitas capacidades interessantes semelhantes no GPT
Como a IA sabe quais testes deve escrever?
É um experimento interessante, mas um tanto suspeito. Acho que a melhor forma de a IA ajudar no desenvolvimento de software é quando o programador faz perguntas sobre seu próprio código ou o código de outras pessoas, e a IA responde. Às vezes isso incluirá sugestões de código, mas não precisa ser sempre assim
Ela deveria ser capaz de responder a perguntas como “há uma forma de simplificar este código?” ou “quais entradas podem causar erros?”
A IA deve nos ajudar a entender o código e a entender como melhorá-lo. Se não dissermos o que queremos que ela faça, a IA não pode saber o que queremos, então não devemos deixá-la escrever tudo sozinha
Testes são um bom exemplo. O que queremos testar?
Finalmente apareceu uma geração de código por IA que faz sentido