Criando um Agente de testes unitários com a linguagem python
Provavelmente você já deve ter criado um sistema básico em algum projeto de programação, mas com certeza tendo ficado com preguiça de executar testes de software, não é mesmo?
Mas antes de continuarmos, vamos esclarecer o que são testes de software e a importância deles em qualquer projeto de desenvolvimento de sistemas
Testes de software e os seus tipos explicados de forma básica
Testes de software são procedimentos de verificação do que foi codificado e serve como uma auditoria do sistema, ou seja para garantir a qualidade do projeto final.
Temos o teste manual, em que os testadores testam a aplicação fora do ambiente de desenvolvimento simulando o papel de um usuário, porém esse teste pode deixar erros de software passarem.
Outros tipos de testes são:
- teste de unidade: em que verifica cada função do sistema de forma separada
- Teste de integração: verifica interação com outras ferramentas ou componentes para o funcionamento integral do sistema
- Teste completo de sistema: faz os teste completo de cada funcionalidade do projeto
O que são agentes de IA e qual é a linguagem mais adequada para iniciantes criarem agentes de IA ?
Eles são sistemas inteligentes projetados para perceber seu ambiente, tomar decisões e executar ações de forma autônoma para atingir um objetivo específico.
Diferente de um sistema tradicional que segue instruções fixas, um agente de IA pode aprender, se adaptar e até mesmo prever necessidades, tornando-o uma ferramenta poderosa tanto no portfólio quanto como acelerador no processo de desenvolvimento de software.
Agora, imagine um agente de IA especializado em testes de software
Um agente de IA nesse campo pode atuar significativamente no desenvolvimento de software e, em particular, nos testes unitários ele pode executar as seguintes ações:
- Implementar o ciclo TDD de forma autônoma: O agente é instruído a seguir as principais etapas do ciclo de Desenvolvimento Orientado a Testes: escrever um teste com falha, escrever o código funcional mínimo para passar no teste e, por fim, refatorar.
- Gerar testes de alta qualidade: Guiado por orientações sobre como escrever bons testes (específicos, isolados, legíveis e rápidos) e formatá-los usando convenções como as do PyTest, o agente cria testes robustos que cobrem diversos cenários.
- Desenvolver código funcional mínimo: O agente é instruído a escrever apenas a quantidade mínima de código necessária para que o teste atual passe, seguindo o princípio do TDD de "código mínimo para passar no teste".
- Identificar e sugerir refatorações: Ele não apenas passa nos testes, mas também é capaz de identificar e sugerir oportunidades de refatoração, buscando melhorias em áreas comuns como duplicação de código, métodos longos, lógica complexa, problemas de nomenclatura e aplicação de padrões de projeto, sempre garantindo que os testes continuem passando após as alterações.
- Iterar e evoluir o código: O agente é capaz de iterar pelo ciclo de TDD para funcionalidades adicionais ou casos extremos, garantindo uma cobertura de testes abrangente e a evolução contínua do software.
Em suma, um agente de IA focado em testes atua como um membro incansável e altamente eficiente da equipe, liberando os desenvolvedores para focar na criação de novas funcionalidades e na arquitetura do sistema, enquanto a qualidade é assegurada de forma proativa. Isso não só acelera o desenvolvimento, mas também eleva a confiabilidade e a manutenção do software.
O Python é sem dúvidas a linguagem mais adequada para criação de agentes de IA e mostrarei isso no passo-a-passo a seguir:
Como eu criei um agente de IA especialista em testes unitários
Primeiro precisamos carregar as bibliotecas para o python começar a trabalhar:
!pip install langchain transformers # ou a biblioteca cliente da API do Gemma
!pip install pytest # para executar os testes
!pip install pytest-asyncio # para executar os testes assíncronos
!pip install google.generativeai
pip install é o instalador de pacotes padrão do python,
langchain é um framework (uma estrutura que facilita o desenvolvimento) projetado para criar aplicativos alimentados por Modelos de Linguagem Grandes ( conhecido por LLMs), como o GPT-4 da OpenAI, o Gemini do Google, ou o próprio Gemma que eu utilizei para criar esse agente.
Como Nosso Agente TDD Ganha Vida?
Nosso Agente TDD não é mágico, mas usa algumas das tecnologias de IA mais avançadas para simular um engenheiro de software:
- Cérebro da IA (Modelo Gemma): Quem faz toda a mágica acontecer é o Gemma, um modelo de linguagem avançado do Google. Ele é o "cérebro" que entende suas instruções, escreve código, gera testes e sugere melhorias. É como ter um programador dedicado e muito rápido!
- “A Cola Inteligente” (LangChain): Para que o Gemma consiga seguir os passos do TDD e "conversar" de forma estruturada, usamos o LangChain. Pense no LangChain como a "cola" que organiza as instruções para o Gemma, garante que ele responda no formato certo (teste, código, refatoração) e facilita a nossa interação com ele.
- Memória Segura (Segredos do Colab): Para que o agente possa se conectar ao Gemma de forma segura, usamos uma "chave secreta" (a API Key). Essa chave é guardada a sete chaves no Google Colab, garantindo que suas credenciais permaneçam privadas, mesmo se você compartilhar o projeto.
Como gerar a chave de API de um modelo de código aberto?
Acesse o seguinte link oficial
após acessar o link, escolha um dos modelos do gemma conforme a imagem abaixo
Como configurar a sua chave de API no Google Colab:
Abra o painel "Secrets" (ícone de chave) no lado esquerdo do Colab veja na imagem abaixo:
Exclua qualquer segredo chamado GOOGLE_API_KEY que já exista (clique nos três pontos ao lado do nome e depois em "Delete").
Adicione um novo segredo:
- Clique em "Add new secret".
- Em "Name", digite EXATAMENTE GOOGLE_API_KEY (maiúsculas e minúsculas importam!).
- Em "Value", cole sua chave de API real do Google AI Studio.
- Certifique-se de que a caixa "Notebook access" esteja MARCADA.
- Clique em "Save".
Após salvar o novo segredo, repita a Solução 1: Reinicie o ambiente de execução (Runtime > Restart runtime) e execute todas as células novamente.
Caso queiram testar o agente que eu criei, mas voces precisarão apenas trocar a chave de API no projeto de vocês conforme mostrei no artigo:
https://colab.research.google.com/drive/1-quIRWtDD8o2nAeON-mhBcQ6xW6LfNtY#scrollTo=el3D4N9LKgE6
Como Usar seu Agente TDD para um Projeto Antigo seu
A ideia é que você apresente uma funcionalidade do seu projeto antigo ao agente, e ele tentará aplicar o ciclo TDD para ela.
Veja como você pode fazer isso:
- Escolha uma Funcionalidade Específica: Selecione uma função, método ou parte lógica do seu projeto antigo que você gostaria de testar ou refatorar. Comece com algo relativamente simples para ver como o agente se comporta.
- Exemplo: "uma função Python que calcula a área de um círculo dado o raio", ou "um método de uma classe que formata um nome completo".
- Use o Prompt Final: Pegue o
final_tdd_agent_prompt_iterative
que criamos por último. - Invoque a Cadeia: Passe a funcionalidade escolhida para a variável
funcionalidade_desejada
ao invocar a cadeia com seu modelo Gemma.
Teste o código abaixo para você testar o agente :
import os
from google.colab import userdata
import google.generativeai as genai
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import SystemMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser
# --- 1. Configurar a Chave de API (usando os Segredos do Colab) ---
try:
api_key = userdata.get('GOOGLE_API_KEY')
if api_key is None:
raise ValueError("A chave 'GOOGLE_API_KEY' não foi encontrada nos Segredos do Colab.")
os.environ['GOOGLE_API_KEY'] = api_key
genai.configure(api_key=os.environ['GOOGLE_API_KEY'])
print("🎉 Chave de API configurada com sucesso a partir dos Segredos do Colab.")
except Exception as e:
print(f"❌ Erro ao configurar a chave de API: {e}")
print("Por favor, verifique se 'GOOGLE_API_KEY' está configurada corretamente nos Segredos do Colab e reinicie o ambiente de execução.")
exit() # Impede que o restante do código seja executado sem a chave.
# --- 2. Instanciando o Modelo Gemma com LangChain ---
# Use o modelo Gemma que você preferir. 'gemma-1.1-7b-it' é um bom ponto de partida.
llm = ChatGoogleGenerativeAI(model="gemma-1.1-7b-it")
print(f"Modelo LangChain instanciado: {llm.model_name}")
# --- 3. O Prompt TDD Final e Completo para o Agente ---
# Este é o prompt que guiará o Gemma através do ciclo TDD.
final_tdd_agent_prompt_iterative = ChatPromptTemplate.from_messages([
SystemMessage(content=(
"Você é um Engenheiro de Software TDD (Desenvolvimento Orientado a Testes) Especialista e rigoroso. "
"Sua missão é me guiar e desenvolver uma funcionalidade específica, seguindo **estritamente** o ciclo TDD.\n\n"
"Para cada solicitação de funcionalidade, você deve apresentar suas respostas em três seções distintas e ordenadas:\n\n"
"### 1. 🔴 Teste (RED - Falha Esperada)\n"
" Ao escrever o TESTE (RED), certifique-se de que ele:\n"
" - É **atômico**: Testa apenas uma funcionalidade ou um pequeno pedaço de lógica por vez.\n"
" - É **reprodutível**: Sempre produz o mesmo resultado, independentemente de onde ou quando é executado.\n"
" - Tem uma **asserção clara**: Usa `assert` para verificar a saída esperada. "
" Pense em casos de uso normais, casos de borda e entradas inválidas (se aplicável).\n"
" - É **legível**: O nome do teste e o código são fáceis de entender.\n"
" - **Formato do código de teste**: Use blocos de código Python (` ```python `) para o teste.\n"
" - Apresente um teste unitário que falhe para a funcionalidade solicitada. "
" - Inclua a razão pela qual este teste é esperado para falhar inicialmente.\n\n"
"### 2. 🟢 Código Funcional (GREEN - Passa no Teste)\n"
" Ao escrever o CÓDIGO FUNCIONAL (GREEN), certifique-se de que:\n"
" - É o **mínimo necessário**: Escreva apenas o código suficiente para que o teste (RED) passe.\n"
" - É **simples e direto**: Evite complexidade desnecessária ou otimizações prematuras.\n"
" - Foca em **passar no teste**: O objetivo primário é transformar o teste de falha para sucesso.\n"
" - **Formato do código funcional**: Use blocos de código Python (` ```python `) para o código.\n"
" - Forneça o código funcional *mínimo e mais simples* que faça o teste anterior passar. "
" - Explique brevemente como este código atende aos requisitos do teste.\n\n"
"### 3. 🔵 Refatoração (BLUE - Melhorias)\n"
" Ao sugerir REFATORAÇÕES (BLUE), certifique-se de que:\n"
" - As refatorações **não alteram o comportamento externo** do código (os testes ainda devem passar).\n"
" - Foque em melhorias de **legibilidade**, **manutenibilidade**, **performance** ou **robustez**.\n"
" - Sugira a adição de **comentários**, **docstrings**, ou **tratamento de erros** (se apropriado).\n"
" - Para cada refatoração, **explique claramente o benefício**.\n"
" - **Formato da refatoração**: Apresente o código refatorado em blocos de código Python (` ```python `) e explique as mudanças.\n\n"
"--- Próximas Iterações ---\n"
" Após completar um ciclo TDD (RED, GREEN, BLUE) para uma funcionalidade, você deve considerar os próximos passos:\n"
" - **Novas funcionalidades**: Se a tarefa inicial implica funcionalidades adicionais, sugira a próxima funcionalidade a ser desenvolvida e o teste (RED) para ela.\n"
" - **Casos de borda/erro**: Identifique e proponha testes (RED) para casos extremos, entradas inválidas ou cenários de erro que o código atual pode não cobrir.\n"
" - **Refatoração contínua**: Avalie se o código ou os testes podem ser refatorados ainda mais para maior clareza ou eficiência.\n"
" - **Indique o próximo ciclo**: Conclua sua resposta sugerindo qual seria o foco do próximo ciclo TDD."
)),
HumanMessage(content="Por favor, inicie o ciclo TDD para a seguinte funcionalidade: {funcionalidade_desejada}")
])
# --- 4. Construindo a Cadeia Final ---
tdd_chain = final_tdd_agent_prompt_iterative | llm | StrOutputParser()
# --- 5. Testando o Agente com uma Funcionalidade do seu Projeto Antigo ---
print("\n--- Iniciando o Agente TDD para uma funcionalidade do seu projeto antigo ---")
# Substitua o texto abaixo pela descrição da funcionalidade do seu projeto antigo!
funcionalidade_para_testar = "uma função Python que calcula a média de uma lista de números, ignorando valores nulos."
try:
print(f"Solicitando ao agente TDD para desenvolver: '{funcionalidade_para_testar}'")
resposta_tdd_agente = tdd_chain.invoke({"funcionalidade_desejada": funcionalidade_para_testar})
print("\n" + "="*80) # Separador visual
print("🚀 Resposta do seu Agente TDD:")
print("="*80 + "\n")
print(resposta_tdd_agente)
print("\n" + "="*80) # Separador visual
except Exception as e:
print(f"❌ Ocorreu um erro ao invocar o agente TDD: {e}")
Observações Importantes:
- Entrada do Agente: Seja o mais claro e específico possível na descrição da
funcionalidade_para_testar
. Quanto mais detalhes você der sobre o que a função deve fazer (inputs, outputs esperados, comportamentos específicos), melhor será a resposta do agente. - Paciência: A geração de LLMs pode levar alguns segundos ou até um minuto, dependendo da complexidade da requisição e da sua conexão.
- Iteração Manual: Lembre-se de que o LLM é um assistente. Ele vai te dar o teste, o código e as refatorações. Você precisará copiar o código de teste, colar em um arquivo
.py
, rodar opytest
, copiar o código funcional, rodarpytest
novamente, e assim por diante. O ciclo TDD com um LLM ainda requer sua intervenção para executar os testes reais.
Obrigado pela atenção, sucesso nos seus projetos!
Fontes consultadas:
TESTE DE SOFTWARE: por onde começar
Tipos de teste em engenharia de software
https://www.linkedin.com/events/7326324075830628352/comments/
https://deepmind.google/models/gemma/?hl=pt-br
Usar modelos abertos do Gemma | Generative AI on Vertex AI | Google Cloud