From 53022df8a4bf0d91812d59a2b47c0bb8db272dab Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Fri, 21 Jun 2024 11:01:42 +0200 Subject: [PATCH] Add sensor tests for APSystems (#117512) --- homeassistant/components/apsystems/sensor.py | 1 + tests/components/apsystems/__init__.py | 11 + tests/components/apsystems/conftest.py | 58 ++- .../apsystems/snapshots/test_sensor.ambr | 460 ++++++++++++++++++ .../components/apsystems/test_config_flow.py | 18 +- tests/components/apsystems/test_sensor.py | 31 ++ 6 files changed, 560 insertions(+), 19 deletions(-) create mode 100644 tests/components/apsystems/snapshots/test_sensor.ambr create mode 100644 tests/components/apsystems/test_sensor.py diff --git a/homeassistant/components/apsystems/sensor.py b/homeassistant/components/apsystems/sensor.py index fdfe7d0f0b7..637def4e418 100644 --- a/homeassistant/components/apsystems/sensor.py +++ b/homeassistant/components/apsystems/sensor.py @@ -132,6 +132,7 @@ class ApSystemsSensorWithDescription( """Base sensor to be used with description.""" entity_description: ApsystemsLocalApiSensorDescription + _attr_has_entity_name = True def __init__( self, diff --git a/tests/components/apsystems/__init__.py b/tests/components/apsystems/__init__.py index 9c3c5990be0..ad86df667ba 100644 --- a/tests/components/apsystems/__init__.py +++ b/tests/components/apsystems/__init__.py @@ -1 +1,12 @@ """Tests for the APsystems Local API integration.""" + +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + + +async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None: + """Fixture for setting up the component.""" + config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(config_entry.entry_id) diff --git a/tests/components/apsystems/conftest.py b/tests/components/apsystems/conftest.py index ab8b7db5a75..cd04346c070 100644 --- a/tests/components/apsystems/conftest.py +++ b/tests/components/apsystems/conftest.py @@ -1,10 +1,16 @@ """Common fixtures for the APsystems Local API tests.""" -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, patch +from APsystemsEZ1 import ReturnDeviceInfo, ReturnOutputData import pytest from typing_extensions import Generator +from homeassistant.components.apsystems.const import DOMAIN +from homeassistant.const import CONF_IP_ADDRESS + +from tests.common import MockConfigEntry + @pytest.fixture def mock_setup_entry() -> Generator[AsyncMock]: @@ -17,13 +23,45 @@ def mock_setup_entry() -> Generator[AsyncMock]: @pytest.fixture -def mock_apsystems(): - """Override APsystemsEZ1M.get_device_info() to return MY_SERIAL_NUMBER as the serial number.""" - ret_data = MagicMock() - ret_data.deviceId = "MY_SERIAL_NUMBER" - with patch( - "homeassistant.components.apsystems.config_flow.APsystemsEZ1M", - return_value=AsyncMock(), - ) as mock_api: - mock_api.return_value.get_device_info.return_value = ret_data +def mock_apsystems() -> Generator[AsyncMock, None, None]: + """Mock APSystems lib.""" + with ( + patch( + "homeassistant.components.apsystems.APsystemsEZ1M", + autospec=True, + ) as mock_client, + patch( + "homeassistant.components.apsystems.config_flow.APsystemsEZ1M", + new=mock_client, + ), + ): + mock_api = mock_client.return_value + mock_api.get_device_info.return_value = ReturnDeviceInfo( + deviceId="MY_SERIAL_NUMBER", + devVer="1.0.0", + ssid="MY_SSID", + ipAddr="127.0.01", + minPower=0, + maxPower=1000, + ) + mock_api.get_output_data.return_value = ReturnOutputData( + p1=2.0, + e1=3.0, + te1=4.0, + p2=5.0, + e2=6.0, + te2=7.0, + ) yield mock_api + + +@pytest.fixture +def mock_config_entry() -> MockConfigEntry: + """Mock config entry.""" + return MockConfigEntry( + domain=DOMAIN, + data={ + CONF_IP_ADDRESS: "127.0.0.1", + }, + unique_id="MY_SERIAL_NUMBER", + ) diff --git a/tests/components/apsystems/snapshots/test_sensor.ambr b/tests/components/apsystems/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..669e89fda17 --- /dev/null +++ b/tests/components/apsystems/snapshots/test_sensor.ambr @@ -0,0 +1,460 @@ +# serializer version: 1 +# name: test_all_entities[sensor.mock_title_lifetime_production_of_p1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_lifetime_production_of_p1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Lifetime production of P1', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'lifetime_production_p1', + 'unique_id': 'MY_SERIAL_NUMBER_lifetime_production_p1', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_lifetime_production_of_p1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Lifetime production of P1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_lifetime_production_of_p1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_lifetime_production_of_p2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_lifetime_production_of_p2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Lifetime production of P2', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'lifetime_production_p2', + 'unique_id': 'MY_SERIAL_NUMBER_lifetime_production_p2', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_lifetime_production_of_p2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Lifetime production of P2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_lifetime_production_of_p2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '7.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_power_of_p1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_power_of_p1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power of P1', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'total_power_p1', + 'unique_id': 'MY_SERIAL_NUMBER_total_power_p1', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_power_of_p1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Mock Title Power of P1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_power_of_p1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_power_of_p2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_power_of_p2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power of P2', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'total_power_p2', + 'unique_id': 'MY_SERIAL_NUMBER_total_power_p2', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_power_of_p2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Mock Title Power of P2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_power_of_p2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_production_of_today', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Production of today', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'today_production', + 'unique_id': 'MY_SERIAL_NUMBER_today_production', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Production of today', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_production_of_today', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '9.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today_from_p1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_production_of_today_from_p1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Production of today from P1', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'today_production_p1', + 'unique_id': 'MY_SERIAL_NUMBER_today_production_p1', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today_from_p1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Production of today from P1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_production_of_today_from_p1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today_from_p2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_production_of_today_from_p2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Production of today from P2', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'today_production_p2', + 'unique_id': 'MY_SERIAL_NUMBER_today_production_p2', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_production_of_today_from_p2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Production of today from P2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_production_of_today_from_p2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '6.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_total_lifetime_production-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_total_lifetime_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total lifetime production', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'lifetime_production', + 'unique_id': 'MY_SERIAL_NUMBER_lifetime_production', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_total_lifetime_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Mock Title Total lifetime production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_total_lifetime_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '11.0', + }) +# --- +# name: test_all_entities[sensor.mock_title_total_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_title_total_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total power', + 'platform': 'apsystems', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'total_power', + 'unique_id': 'MY_SERIAL_NUMBER_total_power', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.mock_title_total_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Mock Title Total power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mock_title_total_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '7.0', + }) +# --- diff --git a/tests/components/apsystems/test_config_flow.py b/tests/components/apsystems/test_config_flow.py index f916240e734..e3fcdf67dcc 100644 --- a/tests/components/apsystems/test_config_flow.py +++ b/tests/components/apsystems/test_config_flow.py @@ -12,7 +12,7 @@ from tests.common import MockConfigEntry async def test_form_create_success( - hass: HomeAssistant, mock_setup_entry, mock_apsystems + hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_apsystems: AsyncMock ) -> None: """Test we handle creatinw with success.""" result = await hass.config_entries.flow.async_init( @@ -28,11 +28,11 @@ async def test_form_create_success( async def test_form_cannot_connect_and_recover( - hass: HomeAssistant, mock_apsystems: AsyncMock, mock_setup_entry + hass: HomeAssistant, mock_apsystems: AsyncMock, mock_setup_entry: AsyncMock ) -> None: """Test we handle cannot connect error.""" - mock_apsystems.return_value.get_device_info.side_effect = TimeoutError + mock_apsystems.get_device_info.side_effect = TimeoutError result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -44,7 +44,7 @@ async def test_form_cannot_connect_and_recover( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": "cannot_connect"} - mock_apsystems.return_value.get_device_info.side_effect = None + mock_apsystems.get_device_info.side_effect = None result2 = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -58,13 +58,13 @@ async def test_form_cannot_connect_and_recover( async def test_form_unique_id_already_configured( - hass: HomeAssistant, mock_setup_entry, mock_apsystems + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_apsystems: AsyncMock, + mock_config_entry: MockConfigEntry, ) -> None: """Test we handle cannot connect error.""" - entry = MockConfigEntry( - domain=DOMAIN, data={CONF_IP_ADDRESS: "127.0.0.2"}, unique_id="MY_SERIAL_NUMBER" - ) - entry.add_to_hass(hass) + mock_config_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, diff --git a/tests/components/apsystems/test_sensor.py b/tests/components/apsystems/test_sensor.py new file mode 100644 index 00000000000..810ad3e7bdf --- /dev/null +++ b/tests/components/apsystems/test_sensor.py @@ -0,0 +1,31 @@ +"""Test the APSystem sensor module.""" + +from unittest.mock import AsyncMock, patch + +from syrupy import SnapshotAssertion + +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, snapshot_platform + + +async def test_all_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + mock_apsystems: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + with patch( + "homeassistant.components.apsystems.PLATFORMS", + [Platform.SENSOR], + ): + await setup_integration(hass, mock_config_entry) + await snapshot_platform( + hass, entity_registry, snapshot, mock_config_entry.entry_id + )