Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .agents/rules/agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
trigger: always_on
glob:
description:
---

File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions .agents/workflows/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
description:
---

Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
description:
---

# Especificação: Arquitetura Hexagonal & DDD

## Visão Geral
Expand Down
File renamed without changes.
File renamed without changes.
33 changes: 33 additions & 0 deletions .github/workflows/backend-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Backend Tests (Pytest)

on:
push:
branches: [ main, master, "feat/**" ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout do Código
uses: actions/checkout@v4

- name: Configurar Python 3.11
uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: Instalar Dependências
run: |
cd backend
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-mock

- name: Rodar Testes com Pytest
run: |
cd backend
export PYTHONPATH=$PYTHONPATH:$(pwd)
pytest
Comment thread
Matheus904-12 marked this conversation as resolved.
4 changes: 3 additions & 1 deletion backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
description="Um serviço de clima com Arquitetura Hexagonal",
version="1.0.0"
)

# CORS
origins = [
"http://localhost:5173",
"http://127.0.0.1:5173",
"http://localhost:5174",
"http://127.0.0.1:5174",
]

app.add_middleware(
Expand Down
Empty file added backend/tests/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions backend/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest
from fastapi.testclient import TestClient
from main import app
from src.domain.entities import WeatherData
Comment on lines +1 to +4

# O TestClient nos permite simular requisições HTTP sem subir o servidor de verdade
client = TestClient(app)

def test_get_weather_endpoint_success(mocker):
"""
Este teste valida se a ROTA /weather/{city} está funcionando corretamente
e se a resposta JSON segue o formato esperado.
"""
# --- ARRANGE ---
# Criamos um dublê do serviço para isolar o teste da API externa
mock_service = mocker.Mock()

fake_weather = WeatherData(
city="Rio de Janeiro", temperature=30.0, description="Ensolarado",
humidity=60, wind_speed=10.0
)
mock_service.execute.return_value = fake_weather

# Injetamos o nosso dublê no estado do App (Injeção de Dependência)
app.state.weather_service = mock_service

# --- ACT ---
# Simulamos uma requisição GET real para o endpoint
response = client.get("/weather/Rio%20de%20Janeiro")

# --- ASSERT ---
# Validamos se o status HTTP é 200 (OK)
assert response.status_code == 200
# Validamos se os dados retornados no JSON estão corretos
data = response.json()
assert data["city"] == "Rio de Janeiro"
assert data["temperature"] == 30.0
assert data["description"] == "Ensolarado"
46 changes: 46 additions & 0 deletions backend/tests/test_use_cases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest
from src.application.use_cases import GetWeatherUseCase
from src.domain.entities import WeatherData

# Teste 1: Garante que o fluxo principal funciona quando os dados são válidos
def tests_get_weather_sucess(mocker):
# --- ARRANGE (Preparação) ---
# Criamos "dublês" (mocks) para não depender de banco de dados ou API real
mock_weather_repo = mocker.Mock()
mock_history_repo = mocker.Mock()

# Simulamos um retorno de clima vindo do "dublê" da API
fake_weather = WeatherData(
city="Paris", temperature=15.0, description="Nuvens", humidity=80, wind_speed=5.0
)
mock_weather_repo.get_weather.return_value = fake_weather

# Injetamos os dublês no Use Case (Injeção de Dependência)
use_case = GetWeatherUseCase(mock_weather_repo, mock_history_repo)

# --- ACT (Ação) ---
# Executamos a lógica que queremos testar
result = use_case.execute("Paris")

# --- ASSERT (Verificação) ---
# Validamos se o resultado é o esperado
assert result.city == "Paris"
assert result.temperature == 15.0
# Importante: Garantimos que o histórico foi SALVO no banco de dados (Mongo)
mock_history_repo.save_search.assert_called_once_with(fake_weather)


# Teste 2: Garante que o sistema barra erros antes de gastar recursos (API/Banco)
def test_get_weather_empty_city_raises_error(mocker):
# --- ARRANGE ---
mock_weather_repo = mocker.Mock()
mock_history_repo = mocker.Mock()
use_case = GetWeatherUseCase(mock_weather_repo, mock_history_repo)

# --- ACT & ASSERT ---
# Verificamos se o sistema lança um erro (ValueError) ao receber cidade vazia
with pytest.raises(ValueError, match="O nome da cidade não pode ser vazio"):
use_case.execute(" ")

# Verificamos que a API de clima NUNCA foi chamada (evita gastos desnecessários)
mock_weather_repo.get_weather.assert_not_called()
Loading