153 lines
5.6 KiB
Python
153 lines
5.6 KiB
Python
"""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!)
|