Estratégia de testes¶
O projeto separa quatro tipos de evidência. A localização sob tests/integration/ não significa, por si só, acesso à rede: o replay de fixtures também mora ali, mas é determinístico e usa mocks.
| Mecanismo | O que verifica | Dependências | Efeito externo |
|---|---|---|---|
| Unit tests | Domínio, aplicação, handlers, adapters, concorrência | pytest, mocks, moto; HTTP simulado nos adapters | Não previsto pelos testes unitários |
| Integration tests | Prompts e decisões de agentes em chamadas reais | OpenAI real e bundle de dependências configurado | Custo OpenAI; outros providers podem ser ativados pela configuração |
| Fixture replay | Uma conversa completa com respostas LLM gravadas e invariantes esperadas | moto e stubs explícitos | Sem OpenAI real |
| Smoke | Configuração, conectividade e contrato operacional de um provider | Credenciais e ambiente real conforme alvo | Leituras de rede e, com flags, envios/escritas |
Execução local sem chamadas reais¶
Com Python 3.12 e o ambiente do projeto ativo:
python -m pip install -e ".[dev]"
python -m pytest tests/unit tests/integration/test_fixture_replay.py -q
Uma seleção equivalente para excluir os cenários OpenAI é:
python -m pytest -m "not integration" -q
O comando por caminhos é mais explícito sobre o conjunto esperado. --no-cov desliga a coleta se ela tiver sido adicionada por configuração externa; o addopts versionado contém apenas -ra --strict-markers.
Seleção de testes e credenciais
tests/integration/test_scenarios.py só é ignorado automaticamente quando OPENAI_API_KEY está ausente. Executar pytest sem filtro com uma chave exportada pode chamar OpenAI. O README histórico apresenta a execução ampla como gratuita; a seleção acima documenta o comportamento atual com segurança.
Convenções e interpretação¶
pyproject.toml registra os markers unit, integration e fixture_replay. Os markers unit e fixture_replay não estão aplicados uniformemente; o próprio test_fixture_replay.py usa parametrização sem marker de replay. Não use -m unit ou -m fixture_replay como substituto da seleção por diretório/arquivo.
passed afirma apenas que as asserções daquele conjunto passaram. skipped significa que um cenário não rodou; deselected indica exclusão pelo filtro. Uma falha em limiar de cobertura é diferente de falha funcional. A contagem e o percentual publicados no README e documentos históricos são fotografias antigas, não resultados desta documentação.
Onde adicionar regressões¶
| Alteração | Teste principal |
|---|---|
| Parser, actions ou transições | tests/unit/application/test_parser.py, test_action_mapping.py; tests/unit/domain/test_states.py |
| Prompt e contrato do invocador | tests/unit/agents/test_system_prompts.py, test_invoker.py |
| Orquestração e latest-message-wins | tests/unit/application/test_process_message_use_case.py; tests/unit/lambdas/test_orchestrator.py |
| Webhook e recibos | tests/unit/lambdas/test_webhook_handler.py |
| Persistência e condições | tests/unit/integrations/test_dynamodb_repos.py |
| CRM durável | tests/unit/application/test_crm_sync.py, tests/unit/lambdas/test_crm_sync.py |
| Atendimento humano | tests/unit/application/test_human_conversation.py; tests/unit/lambdas/test_emulator.py |
| Contrato HTTP de provider | Arquivo test_*_client.py em tests/unit/integrations/ |
| Conversa que regrediu | Fixture em tests/fixtures/conversations/ com o mínimo de turnos que reproduz a falha |
Detalhes: unitários, integração real, fixtures, smokes.