Add forecasting service
This commit is contained in:
135
services/forecasting/tests/test_forecasting.py
Normal file
135
services/forecasting/tests/test_forecasting.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# ================================================================
|
||||
# services/forecasting/tests/test_forecasting.py
|
||||
# ================================================================
|
||||
"""
|
||||
Tests for forecasting service
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import asyncio
|
||||
from datetime import date, datetime, timedelta
|
||||
from unittest.mock import Mock, AsyncMock, patch
|
||||
import uuid
|
||||
|
||||
from app.services.forecasting_service import ForecastingService
|
||||
from app.schemas.forecasts import ForecastRequest, BusinessType
|
||||
from app.models.forecasts import Forecast
|
||||
|
||||
|
||||
class TestForecastingService:
|
||||
"""Test cases for ForecastingService"""
|
||||
|
||||
@pytest.fixture
|
||||
def forecasting_service(self):
|
||||
return ForecastingService()
|
||||
|
||||
@pytest.fixture
|
||||
def sample_forecast_request(self):
|
||||
return ForecastRequest(
|
||||
tenant_id=str(uuid.uuid4()),
|
||||
product_name="Pan Integral",
|
||||
location="madrid_centro",
|
||||
forecast_date=date.today() + timedelta(days=1),
|
||||
business_type=BusinessType.INDIVIDUAL,
|
||||
include_weather=True,
|
||||
include_traffic=True,
|
||||
confidence_level=0.8
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_forecast_success(self, forecasting_service, sample_forecast_request):
|
||||
"""Test successful forecast generation"""
|
||||
|
||||
# Mock database session
|
||||
mock_db = AsyncMock()
|
||||
|
||||
# Mock external dependencies
|
||||
with patch.object(forecasting_service, '_get_latest_model') as mock_get_model, \
|
||||
patch.object(forecasting_service, '_prepare_forecast_features') as mock_prepare_features, \
|
||||
patch.object(forecasting_service.prediction_service, 'predict') as mock_predict, \
|
||||
patch.object(forecasting_service, '_check_and_create_alerts') as mock_check_alerts:
|
||||
|
||||
# Setup mocks
|
||||
mock_get_model.return_value = {
|
||||
"model_id": str(uuid.uuid4()),
|
||||
"version": "1.0.0",
|
||||
"algorithm": "prophet"
|
||||
}
|
||||
|
||||
mock_prepare_features.return_value = {
|
||||
"date": "2024-01-16",
|
||||
"day_of_week": 1,
|
||||
"is_weekend": False,
|
||||
"is_holiday": False,
|
||||
"temperature": 15.0,
|
||||
"precipitation": 0.0
|
||||
}
|
||||
|
||||
mock_predict.return_value = {
|
||||
"demand": 85.5,
|
||||
"lower_bound": 70.2,
|
||||
"upper_bound": 100.8
|
||||
}
|
||||
|
||||
# Execute test
|
||||
result = await forecasting_service.generate_forecast(sample_forecast_request, mock_db)
|
||||
|
||||
# Assertions
|
||||
assert isinstance(result, Forecast)
|
||||
assert result.product_name == "Pan Integral"
|
||||
assert result.predicted_demand == 85.5
|
||||
assert result.confidence_lower == 70.2
|
||||
assert result.confidence_upper == 100.8
|
||||
|
||||
# Verify mocks were called
|
||||
mock_get_model.assert_called_once()
|
||||
mock_prepare_features.assert_called_once()
|
||||
mock_predict.assert_called_once()
|
||||
mock_check_alerts.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_forecast_no_model(self, forecasting_service, sample_forecast_request):
|
||||
"""Test forecast generation when no model is found"""
|
||||
|
||||
mock_db = AsyncMock()
|
||||
|
||||
with patch.object(forecasting_service, '_get_latest_model') as mock_get_model:
|
||||
mock_get_model.return_value = None
|
||||
|
||||
# Should raise ValueError
|
||||
with pytest.raises(ValueError, match="No trained model found"):
|
||||
await forecasting_service.generate_forecast(sample_forecast_request, mock_db)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_prepare_forecast_features(self, forecasting_service, sample_forecast_request):
|
||||
"""Test feature preparation for forecasting"""
|
||||
|
||||
with patch.object(forecasting_service, '_is_spanish_holiday') as mock_holiday, \
|
||||
patch.object(forecasting_service, '_get_weather_forecast') as mock_weather, \
|
||||
patch.object(forecasting_service, '_get_traffic_forecast') as mock_traffic:
|
||||
|
||||
# Setup mocks
|
||||
mock_holiday.return_value = False
|
||||
mock_weather.return_value = {
|
||||
"temperature": 18.5,
|
||||
"precipitation": 0.0,
|
||||
"humidity": 65.0,
|
||||
"weather_description": "Clear"
|
||||
}
|
||||
mock_traffic.return_value = {
|
||||
"traffic_volume": 1200,
|
||||
"pedestrian_count": 850
|
||||
}
|
||||
|
||||
# Execute test
|
||||
features = await forecasting_service._prepare_forecast_features(sample_forecast_request)
|
||||
|
||||
# Assertions
|
||||
assert "date" in features
|
||||
assert "day_of_week" in features
|
||||
assert "is_weekend" in features
|
||||
assert "is_holiday" in features
|
||||
assert features["business_type"] == "individual"
|
||||
assert features["temperature"] == 18.5
|
||||
assert features["traffic_volume"] == 1200
|
||||
|
||||
Reference in New Issue
Block a user