initial commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""Test configuration and fixtures for elprisenligenu tests."""
|
||||
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_configure(config: pytest.Config) -> None:
|
||||
"""Configure pytest with custom markers."""
|
||||
config.addinivalue_line(
|
||||
"markers",
|
||||
"integration: marks tests as integration tests (may require internet)",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_api_response() -> list[dict]:
|
||||
"""Fixture providing a mock API response."""
|
||||
return [
|
||||
{
|
||||
"DKK_per_kWh": 1.3929,
|
||||
"EUR_per_kWh": 0.18729,
|
||||
"EXR": 7.437118,
|
||||
"time_start": "2024-10-29T00:00:00+01:00",
|
||||
"time_end": "2024-10-29T01:00:00+01:00",
|
||||
},
|
||||
{
|
||||
"DKK_per_kWh": 1.30291,
|
||||
"EUR_per_kWh": 0.17519,
|
||||
"EXR": 7.437118,
|
||||
"time_start": "2024-10-29T01:00:00+01:00",
|
||||
"time_end": "2024-10-29T02:00:00+01:00",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_hour_data() -> dict:
|
||||
"""Fixture providing sample HourData for testing."""
|
||||
|
||||
tz = ZoneInfo("Europe/Copenhagen")
|
||||
return {
|
||||
"DKK_per_kWh": 1.2345,
|
||||
"EUR_per_kWh": 0.1659,
|
||||
"EXR": 7.4371,
|
||||
"time_start": datetime(2024, 10, 29, 12, 0, 0, tzinfo=tz),
|
||||
"time_end": datetime(2024, 10, 29, 13, 0, 0, tzinfo=tz),
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
"""Integration tests for the elprisenligenu module."""
|
||||
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytest
|
||||
|
||||
from elprisenligenu.api import API
|
||||
from elprisenligenu.dto.hour_data import HourData
|
||||
|
||||
|
||||
class TestElprisenLigenIntegration:
|
||||
"""Integration tests that make real API calls."""
|
||||
|
||||
def setup_method(self) -> None:
|
||||
"""Set up test fixtures before each test method."""
|
||||
self.api = API()
|
||||
self.tz = ZoneInfo("Europe/Copenhagen")
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_get_current_prices_dk1(self) -> None:
|
||||
"""Test fetching current day prices for DK1 (integration test)."""
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK1")
|
||||
|
||||
# Assert
|
||||
assert isinstance(result, list)
|
||||
assert all(isinstance(item, HourData) for item in result)
|
||||
|
||||
if result: # If data is available
|
||||
first_hour = result[0]
|
||||
assert isinstance(first_hour.DKK_per_kWh, float)
|
||||
assert isinstance(first_hour.EUR_per_kWh, float)
|
||||
assert isinstance(first_hour.EXR, float)
|
||||
assert isinstance(first_hour.time_start, datetime)
|
||||
assert isinstance(first_hour.time_end, datetime)
|
||||
|
||||
# Basic sanity checks
|
||||
assert first_hour.EXR > 0 # Exchange rate should be positive
|
||||
assert first_hour.time_start < first_hour.time_end
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_get_current_prices_dk2(self) -> None:
|
||||
"""Test fetching current day prices for DK2 (integration test)."""
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK2")
|
||||
|
||||
# Assert
|
||||
assert isinstance(result, list)
|
||||
assert all(isinstance(item, HourData) for item in result)
|
||||
|
||||
if result: # If data is available
|
||||
first_hour = result[0]
|
||||
assert isinstance(first_hour.DKK_per_kWh, float)
|
||||
assert isinstance(first_hour.EUR_per_kWh, float)
|
||||
assert isinstance(first_hour.EXR, float)
|
||||
assert isinstance(first_hour.time_start, datetime)
|
||||
assert isinstance(first_hour.time_end, datetime)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_get_historical_prices(self) -> None:
|
||||
"""Test fetching historical prices (integration test)."""
|
||||
# Arrange - Use a date that should have data (not too far back)
|
||||
historical_date = datetime(2024, 10, 1, tzinfo=self.tz)
|
||||
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK1", date=historical_date)
|
||||
|
||||
# Assert
|
||||
assert isinstance(result, list)
|
||||
|
||||
if result: # If historical data is available
|
||||
assert len(result) <= 24 # Should be max 24 hours
|
||||
assert all(isinstance(item, HourData) for item in result)
|
||||
|
||||
# Check that all times are from the requested date
|
||||
for hour_data in result:
|
||||
assert hour_data.time_start.date() == historical_date.date()
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_price_consistency(self) -> None:
|
||||
"""Test that EUR and DKK prices are consistent with exchange rate."""
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK1")
|
||||
|
||||
# Assert
|
||||
if result:
|
||||
for hour_data in result:
|
||||
# Calculate expected DKK price from EUR price and exchange rate
|
||||
expected_dkk = hour_data.EUR_per_kWh * hour_data.EXR
|
||||
|
||||
# Allow for small floating point differences
|
||||
difference = abs(hour_data.DKK_per_kWh - expected_dkk)
|
||||
assert difference < 0.001, (
|
||||
f"Price inconsistency: DKK={hour_data.DKK_per_kWh}, "
|
||||
f"EUR={hour_data.EUR_per_kWh}, EXR={hour_data.EXR}, "
|
||||
f"Expected DKK={expected_dkk}"
|
||||
)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_time_ordering(self) -> None:
|
||||
"""Test that hours are returned in chronological order."""
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK1")
|
||||
|
||||
# Assert
|
||||
if len(result) > 1:
|
||||
for i in range(1, len(result)):
|
||||
assert result[i - 1].time_start <= result[i].time_start, (
|
||||
f"Hours not in chronological order: "
|
||||
f"{result[i - 1].time_start} > {result[i].time_start}"
|
||||
)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_hour_duration(self) -> None:
|
||||
"""Test that each hour period is exactly 1 hour long."""
|
||||
# Act
|
||||
result = self.api.get_daily_prices(zone="DK1")
|
||||
|
||||
# Assert
|
||||
if result:
|
||||
for hour_data in result:
|
||||
duration = hour_data.time_end - hour_data.time_start
|
||||
assert duration.total_seconds() == 3600, (
|
||||
f"Hour duration is not 1 hour: {duration}"
|
||||
)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_both_zones_same_day(self) -> None:
|
||||
"""Test that both zones return data for the same day."""
|
||||
# Arrange
|
||||
test_date = datetime(2024, 10, 15, tzinfo=self.tz)
|
||||
|
||||
# Act
|
||||
dk1_result = self.api.get_daily_prices(zone="DK1", date=test_date)
|
||||
dk2_result = self.api.get_daily_prices(zone="DK2", date=test_date)
|
||||
|
||||
# Assert
|
||||
# Both zones should have data for the same day
|
||||
if dk1_result and dk2_result:
|
||||
assert len(dk1_result) == len(dk2_result)
|
||||
|
||||
# Times should be the same
|
||||
for dk1_hour, dk2_hour in zip(dk1_result, dk2_result):
|
||||
assert dk1_hour.time_start == dk2_hour.time_start
|
||||
assert dk1_hour.time_end == dk2_hour.time_end
|
||||
|
||||
# Exchange rates should be the same
|
||||
assert dk1_hour.EXR == dk2_hour.EXR
|
||||
|
||||
# But prices can be different between zones
|
||||
# (That's the whole point of having two zones!)
|
||||
Reference in New Issue
Block a user