Add unit test for sensors in swiss public transport (#134115)

* add unit test for sensors

* clean up
This commit is contained in:
Cyrill Raccaud 2024-12-27 21:21:45 +01:00 committed by GitHub
parent 375af6cb1c
commit bb8d4ca255
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 576 additions and 0 deletions

View File

@ -1,10 +1,57 @@
"""Common fixtures for the swiss_public_transport tests."""
from collections.abc import Generator
import json
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.swiss_public_transport.const import (
CONF_DESTINATION,
CONF_START,
DOMAIN,
)
from tests.common import MockConfigEntry, load_fixture
START = "Zürich"
DESTINATION = "Bern"
@pytest.fixture
def mock_opendata_client() -> Generator[AsyncMock]:
"""Mock a Opendata client."""
with (
patch(
"homeassistant.components.swiss_public_transport.OpendataTransport",
autospec=True,
) as mock_client,
patch(
"homeassistant.components.swiss_public_transport.config_flow.OpendataTransport",
new=mock_client,
),
):
client = mock_client.return_value
client.async_get_data.return_value = None
client.from_name = START
client.to_name = DESTINATION
client.connections = json.loads(load_fixture("connections.json", DOMAIN))[0:3]
yield client
@pytest.fixture(name="swiss_public_transport_config_entry")
def mock_swiss_public_transport_config_entry() -> MockConfigEntry:
"""Mock cookidoo configuration entry."""
return MockConfigEntry(
domain=DOMAIN,
data={
CONF_START: START,
CONF_DESTINATION: DESTINATION,
},
title=f"{START} {DESTINATION}",
entry_id="01JBVVVJ87F6G5V0QJX6HBC94T",
)
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:

View File

@ -0,0 +1,384 @@
# serializer version: 1
# name: test_all_entities[sensor.zurich_bern_delay-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_delay',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Delay',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'delay',
'unique_id': 'Zürich Bern_delay',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
})
# ---
# name: test_all_entities[sensor.zurich_bern_delay-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'device_class': 'duration',
'friendly_name': 'Zürich Bern Delay',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_delay',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_departure',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Departure',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'departure0',
'unique_id': 'Zürich Bern_departure',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'device_class': 'timestamp',
'friendly_name': 'Zürich Bern Departure',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_departure',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2024-01-06T17:03:00+00:00',
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure_1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_departure_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Departure +1',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'departure1',
'unique_id': 'Zürich Bern_departure1',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'device_class': 'timestamp',
'friendly_name': 'Zürich Bern Departure +1',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_departure_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2024-01-06T17:04:00+00:00',
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure_2-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_departure_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Departure +2',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'departure2',
'unique_id': 'Zürich Bern_departure2',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_departure_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'device_class': 'timestamp',
'friendly_name': 'Zürich Bern Departure +2',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_departure_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2024-01-06T17:05:00+00:00',
})
# ---
# name: test_all_entities[sensor.zurich_bern_duration-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_duration',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Duration',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'Zürich Bern_duration',
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
})
# ---
# name: test_all_entities[sensor.zurich_bern_duration-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'device_class': 'duration',
'friendly_name': 'Zürich Bern Duration',
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_duration',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '10',
})
# ---
# name: test_all_entities[sensor.zurich_bern_line-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_line',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Line',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'line',
'unique_id': 'Zürich Bern_line',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_line-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'friendly_name': 'Zürich Bern Line',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_line',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'T10',
})
# ---
# name: test_all_entities[sensor.zurich_bern_platform-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_platform',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Platform',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'platform',
'unique_id': 'Zürich Bern_platform',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_platform-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'friendly_name': 'Zürich Bern Platform',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_platform',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_all_entities[sensor.zurich_bern_transfers-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.zurich_bern_transfers',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Transfers',
'platform': 'swiss_public_transport',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'transfers',
'unique_id': 'Zürich Bern_transfers',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.zurich_bern_transfers-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by transport.opendata.ch',
'friendly_name': 'Zürich Bern Transfers',
}),
'context': <ANY>,
'entity_id': 'sensor.zurich_bern_transfers',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---

View File

@ -0,0 +1,145 @@
"""Tests for the swiss_public_transport sensor platform."""
import json
from unittest.mock import AsyncMock, patch
from opendata_transport.exceptions import (
OpendataTransportConnectionError,
OpendataTransportError,
)
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.swiss_public_transport.const import (
DEFAULT_UPDATE_TIME,
DOMAIN,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import (
MockConfigEntry,
async_fire_time_changed,
load_fixture,
snapshot_platform,
)
from tests.test_config_entries import FrozenDateTimeFactory
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_opendata_client: AsyncMock,
swiss_public_transport_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
with patch("homeassistant.components.cookidoo.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, swiss_public_transport_config_entry)
assert swiss_public_transport_config_entry.state is ConfigEntryState.LOADED
await snapshot_platform(
hass, entity_registry, snapshot, swiss_public_transport_config_entry.entry_id
)
@pytest.mark.parametrize(
("raise_error"),
[OpendataTransportConnectionError, OpendataTransportError],
)
async def test_fetching_data(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
mock_opendata_client: AsyncMock,
swiss_public_transport_config_entry: MockConfigEntry,
raise_error: Exception,
) -> None:
"""Test fetching data."""
await setup_integration(hass, swiss_public_transport_config_entry)
assert swiss_public_transport_config_entry.state is ConfigEntryState.LOADED
mock_opendata_client.async_get_data.assert_called()
assert mock_opendata_client.async_get_data.call_count == 2
assert len(hass.states.async_all(SENSOR_DOMAIN)) == 8
assert (
hass.states.get("sensor.zurich_bern_departure").state
== "2024-01-06T17:03:00+00:00"
)
assert (
hass.states.get("sensor.zurich_bern_departure_1").state
== "2024-01-06T17:04:00+00:00"
)
assert (
hass.states.get("sensor.zurich_bern_departure_2").state
== "2024-01-06T17:05:00+00:00"
)
assert hass.states.get("sensor.zurich_bern_duration").state == "10"
assert hass.states.get("sensor.zurich_bern_platform").state == "0"
assert hass.states.get("sensor.zurich_bern_transfers").state == "0"
assert hass.states.get("sensor.zurich_bern_delay").state == "0"
assert hass.states.get("sensor.zurich_bern_line").state == "T10"
# Set new data and verify it
mock_opendata_client.connections = json.loads(
load_fixture("connections.json", DOMAIN)
)[3:6]
freezer.tick(DEFAULT_UPDATE_TIME)
async_fire_time_changed(hass)
assert mock_opendata_client.async_get_data.call_count == 3
assert (
hass.states.get("sensor.zurich_bern_departure").state
== "2024-01-06T17:06:00+00:00"
)
# Simulate fetch exception
mock_opendata_client.async_get_data.side_effect = raise_error
freezer.tick(DEFAULT_UPDATE_TIME)
async_fire_time_changed(hass)
assert mock_opendata_client.async_get_data.call_count == 4
assert hass.states.get("sensor.zurich_bern_departure").state == "unavailable"
# Recover and fetch new data again
mock_opendata_client.async_get_data.side_effect = None
mock_opendata_client.connections = json.loads(
load_fixture("connections.json", DOMAIN)
)[6:9]
freezer.tick(DEFAULT_UPDATE_TIME)
async_fire_time_changed(hass)
assert mock_opendata_client.async_get_data.call_count == 5
assert (
hass.states.get("sensor.zurich_bern_departure").state
== "2024-01-06T17:09:00+00:00"
)
@pytest.mark.parametrize(
("raise_error", "state"),
[
(OpendataTransportConnectionError, ConfigEntryState.SETUP_RETRY),
(OpendataTransportError, ConfigEntryState.SETUP_ERROR),
],
)
async def test_fetching_data_setup_exception(
hass: HomeAssistant,
mock_opendata_client: AsyncMock,
swiss_public_transport_config_entry: MockConfigEntry,
raise_error: Exception,
state: ConfigEntryState,
) -> None:
"""Test fetching data with setup exception."""
mock_opendata_client.async_get_data.side_effect = raise_error
await setup_integration(hass, swiss_public_transport_config_entry)
assert swiss_public_transport_config_entry.state is state