Introdução aos Testes no Sapling SCM
O Sapling SCM é um sistema de controle de versão (Source Control Management) desenvolvido pelo Facebook, projetado para escalabilidade e compatibilidade com Git. Ele oferece uma interface robusta e amigável, capaz de gerenciar repositórios de vastas dimensões, com milhões de arquivos e commits. Este guia detalha as metodologias e as melhores práticas para a criação de testes dentro do ecossistema do projeto Sapling.
Arquitetura do Framework de Testes
Estrutura de Diretórios
eden/scm/tests/
├── test-*.t # Arquivos de teste de funcionalidade via linha de comando
├── test-*.py # Arquivos de teste unitário em Python
├── run-tests.py # Script executor de testes
├── README # Documentação dos testes
└── Diversos arquivos auxiliares e utilitários
Classificação dos Tipos de Teste
| Tipo de Teste |
Extensão do Arquivo |
Descrição |
Cenários de Aplicação |
| Testes de Linha de Comando |
.t |
Testes de integração baseados em comandos shell. |
Validação de funcionalidades, testes de ponta a ponta. |
| Testes Unitários Python |
.py |
Testes de código em nível de unidade. |
Verificação de módulos, validação de algoritmos. |
| Testes de Performance |
.py |
Avaliação de desempenho e benchmarks. |
Monitoramento de performance, validação de otimizações. |
| Testes de Compatibilidade |
.t |
Testes de compatibilidade entre plataformas. |
Validação de suporte multiplataforma. |
Diretrizes para a Escrita de Testes
1. Testes de Linha de Comando (.t)
Sintaxe Fundamental
#require requisito-funcional
#debugruntest-compatible
$ Comando de inicialização
$ Comando de teste principal
Saída esperada
[Código de saída]
#if condição-específica
$ Comando de teste condicional
Saída condicional esperada
#endif
Exemplo Prático
#require no-eden
$ hg init projeto_teste
$ cd projeto_teste
$ echo "primeiro arquivo de teste" > doc_inicial.txt
$ hg add doc_inicial.txt
$ hg status
A doc_inicial.txt
$ hg commit -m "Commit inicial do documento"
$ hg log -T "{desc}\n"
Commit inicial do documento
2. Testes Unitários em Python (.py)
Estrutura da Classe de Teste
from __future__ import absolute_import
import unittest
# Assumindo um módulo para lógica e erros
from sapling.util import processador, validacao_erro
class TesteServicoProcessamento(unittest.TestCase):
def setUp(self):
"""Prepara dados para cada teste."""
self.dados_validos = {"id": 1, "status": "pendente"}
def test_processamento_simples(self):
"""Verifica o processamento bem-sucedido de dados válidos."""
resultado = processador.executar(self.dados_validos)
self.assertIsNotNone(resultado)
self.assertEqual(resultado["status"], "concluido")
def test_dados_invalidos_geram_erro(self):
"""Testa o comportamento com entrada inválida."""
with self.assertRaises(validacao_erro.InvalidInputError):
processador.executar(None)
Melhores Práticas na Criação de Testes
1. Princípios de Design de Casos de Teste
Ao elaborar casos de teste, priorize a clareza, a atomicidade e a reprodutibilidade. Cada teste deve focar em uma única funcionalidade ou condição, garantindo que falhas sejam facilmente identificáveis. Considere cenários normais, limites e casos de erro para uma cobertura abrangente.
2. Gerenciamento de Dados de Teste
| Tipo de Dados |
Método de Gerenciamento |
Exemplo |
| Dados Estáticos |
Inclusão direta no arquivo de teste. |
$ echo "dado_fixo" > arquivo.txt |
| Dados Dinâmicos |
Geração programática via Python. |
dados_teste = gerador_dados_mock() |
| Grandes Conjuntos de Dados |
Armazenamento em arquivos externos. |
Arquivos no diretório recursos/ |
| Dados Sensíveis |
Utilização de mocks ou placeholders. |
mock_informacao_usuario() |
3. Criação de Testes Condicionais
#if unix-permissions
$ touch script_executavel.sh
$ chmod +x script_executavel.sh
$ hg add script_executavel.sh
$ hg status
A script_executavel.sh
#endif
#if windows
$ echo "Conteúdo específico para Windows" > arquivo_win.txt
$ hg add arquivo_win.txt
#endif
Técnicas Avançadas de Teste
1. Modo de Teste em Lote
def test_operacoes_em_lote(self):
"""Verifica a execução e os resultados de operações em lote."""
executor_lote = some_batch_lib.BatchExecutor()
tarefa_a = executor_lote.adicionar_tarefa("processar_dados", dados={"valor1": 10, "valor2": 20})
tarefa_b = executor_lote.adicionar_tarefa("validar_config", config={"modo": "seguro"})
executor_lote.executar_todas()
resultados_a = tarefa_a.obter_resultado()
resultados_b = tarefa_b.obter_resultado()
self.assertEqual(resultados_a["status"], "sucesso")
self.assertTrue(resultados_b["validado"])
2. Tratamento de Testes Assíncronos
async def test_servico_assincrono(self):
"""Assegura a correta execução de um serviço assíncrono."""
status_servico = await servico_remoto.iniciar_e_monitorar()
self.assertIn("ID_transacao", status_servico)
self.assertEqual(status_servico["estado"], "finalizado")
3. Base de Performance para Testes
def test_desempenho_funcao_intensiva(self):
"""Avalia o tempo de execução de uma função com carga computacional."""
import time
inicio_medicao = time.perf_counter() # Usando perf_counter para precisão
num_operacoes = 500 # Reduzindo iterações para demonstrar mudança
for _ in range(num_operacoes):
calculo_complexo.executar()
fim_medicao = time.perf_counter()
tempo_decorrido = fim_medicao - inicio_medicao
self.assertLess(tempo_decorrido, 0.5) # Novo limite de tempo
Execução e Depuração de Testes
1. Comandos para Executar Testes
# Para executar todos os testes
cd eden/scm/tests/
python run-tests.py
# Para executar um teste específico
python run-tests.py test-adicionar.t
python run-tests.py test-processamento_lote.py
# Para executar testes em paralelo
python run-tests.py -j4 # Utiliza 4 processos
# Para executar em modo de depuração
python run-tests.py -d test-especifico.t
2. Dicas para Depuração de Testes
# Adicionar saída de depuração no teste
$ hg comando --debug
debug: Detalhes da execução
Saída normal
# Depuração com arquivos temporários
$ hg status > /tmp/saida_depuracao.txt
$ cat /tmp/saida_depuracao.txt
Informações de status do arquivo
3. Análise de Cobertura de Teste
# Gerar relatório de cobertura de teste
python run-tests.py -c # Relatório no console
python run-tests.py -H # Relatório em formato HTML
python run-tests.py -C # Relatório anotado
Problemas Comuns e Soluções
1. Problemas de Ambiente de Teste
| Tipo de Problema |
Sintoma |
Solução Proposta |
| Questões de Permissão |
Permissão negada (Permission denied) |
Usar a diretiva #require para ignorar o teste se a permissão não for aplicável. |
| Recursos Insuficientes |
Muitos arquivos abertos (Too many open files) |
Aumentar o limite de descritores de arquivo do sistema operacional. |
| Diferenças de Plataforma |
Teste falha em um SO, mas passa em outro |
Implementar testes condicionais com #if para plataformas específicas. |
2. Questões de Estabilidade de Teste
def test_acesso_concorrente_a_recurso(self):
"""Verifica a integridade de um recurso compartilhado sob acesso concorrente."""
import threading
contador_compartilhado = {"valor": 0}
lock_recurso = threading.Lock()
def incrementar_recurso():
with lock_recurso:
contador_compartilhado["valor"] += 1
num_threads = 5
threads_exec = [threading.Thread(target=incrementar_recurso) for _ in range(num_threads)]
for t_exec in threads_exec:
t_exec.start()
for t_exec in threads_exec:
t_exec.join()
self.assertEqual(contador_compartilhado["valor"], num_threads)
3. Contaminação de Dados de Teste
# Assegurar isolamento entre testes
$ hg init ambiente_isolado
$ cd ambiente_isolado
# Executa operações de teste aqui...
$ cd ..
$ rm -rf ambiente_isolado # Remove o diretório de teste
Critérios de Avaliação da Qualidade do Teste
1. Métricas de Cobertura de Teste
A cobertura de teste é um indicador chave da profundidade dos testes. Métricas como cobertura de linha, ramo e condição auxiliam na identificação de áreas do código que necessitam de maior atenção. Ferrmaentas automatizadas devem ser usadas para gerar e monitorar esses relatórios, garantindo uma visão clara do que está e não está sendo testado.
2. Requisitos de Taxa de Aprovação dos Testes
| Tipo de Teste |
Taxa de Aprovação Requerida |
Observações |
| Testes Unitários |
100% |
Todos os testes devem ser aprovados sem falhas. |
| Testes de Integração |
≥ 95% |
Pode haver uma pequena margem para problemas conhecidos e justificados. |
| Testes de Performance |
≥ 90% |
Permite variações devido a fatores ambientais. |
| Testes de Compatibilidade |
≥ 85% |
Tolerância para diferenças inerentes a múltiplas plataformas. |
Integração Contínua (CI)
1. Configuração da Pipeline de CI
# Exemplo de configuração de CI
testes_sapling:
stage: test
script:
- cd eden/scm/tests/
- python run-tests.py -j4
- python run-tests.py -c # Verificação de cobertura
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: cobertura_sapling.xml
2. Monitoramento de Resultados de Teste
| Métrica de Monitoramento |
Limiar de Alerta |
Ações Sugeridas |
| Taxa de Aprovação de Testes |
< 95% |
Investigar imediatamente a causa das falhas. |
| Tempo de Execução de Testes |
> 30 minutos |
Analisar e otimizar o desempenho dos testes. |
| Queda na Cobertura |
> 5% |
Verificar a cobertura de código recém-adicionado. |
| Regressão de Performance |
> 20% |
Realizar análise de performance e otimizações. |