Skip to main content

Guia de Testes

Estrutura

tests/
├── unit/
│ ├── test_models.py
│ ├── test_diff_parser.py
│ ├── test_position_mapper.py
│ ├── test_review_pipeline.py
│ ├── test_validation.py
│ ├── test_logging_config.py
│ ├── test_nvidia_nim_client.py
│ ├── test_gitlab_rest_client.py
│ ├── test_background_tasks_dispatcher.py
│ ├── test_lambda_self_invoke_dispatcher.py
│ ├── test_router.py
│ ├── test_app_entrypoint.py
│ └── test_lambda_handler.py
└── integration/
└── test_webapp_integration.py

Rodar testes

# Todos
pytest -v

# Só unitários
pytest tests/unit/ -v

# Só integração
pytest tests/integration/ -v

# Arquivo específico
pytest tests/unit/test_models.py -v

# Com cobertura
pytest --cov=src --cov-report=term-missing

Convenções

Arrange-Act-Assert

def test_maps_addition_line_to_position():
# Arrange
file_diff = parse_file_diff("a.py", "a.py", "@@ -1,1 +1,2 @@\n line\n+new\n")
finding = Finding(line=2, severity="high", category="bug", message="msg")

# Act
position = map_finding_to_position(file_diff, finding, _event())

# Assert
assert position["new_line"] == 2

Fakes vs Mocks

O projeto usa Fakes (classes manuais) ao invés de mocks bibliotecários:

class FakeGitlabClient:
def __init__(self, file_diffs=None):
self.file_diffs = file_diffs or []
self.inline_comments = []

def fetch_diff(self, event):
return self.file_diffs

def post_inline_comment(self, event, finding, position):
self.inline_comments.append((position["new_path"], finding.line))

Por quê? Fakes são mais explícitos, fácils de ler e não dependem de APIs mágicas.

Testes assíncronos

Para testes com asyncio:

@pytest.mark.asyncio
async def test_dispatch_runs_pipeline():
pipeline = _FakePipeline()
dispatcher = BackgroundTaskDispatcher(pipeline)

dispatcher.dispatch(_event())
await asyncio.sleep(0.05) # Aguarda a task completar

assert len(pipeline.calls) == 1

HTTP mocking

Para testes que chamam APIs externas, use a lib responses:

@responses.activate
def test_fetch_diff_parses_changes():
responses.add(
responses.GET,
"https://gitlab.example.com/api/v4/projects/1/merge_requests/2/changes",
json={"changes": [...]},
status=200,
)
client = GitlabRestClient(base_url=BASE_URL, token="tok")
result = client.fetch_diff(_event())
assert len(result) == 1

Adicionando novos testes

  1. Crie o arquivo em tests/unit/ ou tests/integration/
  2. Siga o padrão test_<descrição>.py
  3. Use factories para criar objetos de teste
  4. Um teste por cenário
  5. Nome descritivo: test_<o_que>_when_<condição>