Refactor V2C tests (#117264)

* Refactor V2C tests

* Refactor V2C tests

* Refactor V2C tests

* Refactor V2C tests

* Update tests/components/v2c/conftest.py

* Refactor V2C tests
This commit is contained in:
Joost Lekkerkerker 2024-05-11 21:28:37 +02:00 committed by GitHub
parent 7eb8f265fe
commit 9f53c807c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 391 additions and 52 deletions

View file

@ -1 +1,11 @@
"""Tests for the V2C integration.""" """Tests for the V2C integration."""
from tests.common import MockConfigEntry
async def init_integration(hass, config_entry: MockConfigEntry) -> MockConfigEntry:
"""Set up the V2C integration in Home Assistant."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

View file

@ -4,6 +4,12 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
import pytest import pytest
from pytrydan.models.trydan import TrydanData
from homeassistant.components.v2c import DOMAIN
from homeassistant.const import CONF_HOST
from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture @pytest.fixture
@ -13,3 +19,33 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"homeassistant.components.v2c.async_setup_entry", return_value=True "homeassistant.components.v2c.async_setup_entry", return_value=True
) as mock_setup_entry: ) as mock_setup_entry:
yield mock_setup_entry yield mock_setup_entry
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Define a config entry fixture."""
return MockConfigEntry(
domain=DOMAIN,
entry_id="da58ee91f38c2406c2a36d0a1a7f8569",
title="EVSE 1.1.1.1",
data={CONF_HOST: "1.1.1.1"},
)
@pytest.fixture
def mock_v2c_client() -> Generator[AsyncMock, None, None]:
"""Mock a V2C client."""
with (
patch(
"homeassistant.components.v2c.Trydan",
autospec=True,
) as mock_client,
patch(
"homeassistant.components.v2c.config_flow.Trydan",
new=mock_client,
),
):
client = mock_client.return_value
get_data_json = load_json_object_fixture("get_data.json", DOMAIN)
client.get_data.return_value = TrydanData.from_api(get_data_json)
yield client

View file

@ -0,0 +1,23 @@
{
"ID": "ABC123",
"ChargeState": 2,
"ReadyState": 0,
"ChargePower": 1500.27,
"ChargeEnergy": 1.8,
"SlaveError": 4,
"ChargeTime": 4355,
"HousePower": 0.0,
"FVPower": 0.0,
"BatteryPower": 0.0,
"Paused": 0,
"Locked": 0,
"Timer": 0,
"Intensity": 6,
"Dynamic": 0,
"MinIntensity": 6,
"MaxIntensity": 16,
"PauseDynamic": 0,
"FirmwareVersion": "2.1.7",
"DynamicPowerMode": 2,
"ContractedPower": 4600
}

View file

@ -0,0 +1,257 @@
# serializer version: 1
# name: test_sensor[sensor.evse_1_1_1_1_charge_energy-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.evse_1_1_1_1_charge_energy',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Charge energy',
'platform': 'v2c',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charge_energy',
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_charge_energy',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_charge_energy-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'EVSE 1.1.1.1 Charge energy',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.evse_1_1_1_1_charge_energy',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.8',
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_charge_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.evse_1_1_1_1_charge_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': 'mdi:ev-station',
'original_name': 'Charge power',
'platform': 'v2c',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charge_power',
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_charge_power',
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_charge_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': 'EVSE 1.1.1.1 Charge power',
'icon': 'mdi:ev-station',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
}),
'context': <ANY>,
'entity_id': 'sensor.evse_1_1_1_1_charge_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1500.27',
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_charge_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.evse_1_1_1_1_charge_time',
'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': 'Charge time',
'platform': 'v2c',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charge_time',
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_charge_time',
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_charge_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'EVSE 1.1.1.1 Charge time',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
}),
'context': <ANY>,
'entity_id': 'sensor.evse_1_1_1_1_charge_time',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '4355',
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_house_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.evse_1_1_1_1_house_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': None,
'original_name': 'House power',
'platform': 'v2c',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'house_power',
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_house_power',
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_house_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': 'EVSE 1.1.1.1 House power',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
}),
'context': <ANY>,
'entity_id': 'sensor.evse_1_1_1_1_house_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_photovoltaic_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.evse_1_1_1_1_photovoltaic_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': None,
'original_name': 'Photovoltaic power',
'platform': 'v2c',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'fv_power',
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_fv_power',
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
})
# ---
# name: test_sensor[sensor.evse_1_1_1_1_photovoltaic_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': 'EVSE 1.1.1.1 Photovoltaic power',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
}),
'context': <ANY>,
'entity_id': 'sensor.evse_1_1_1_1_photovoltaic_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---

View file

@ -1,41 +1,36 @@
"""Test the V2C config flow.""" """Test the V2C config flow."""
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock
import pytest import pytest
from pytrydan.exceptions import TrydanError from pytrydan.exceptions import TrydanError
from homeassistant import config_entries
from homeassistant.components.v2c.const import DOMAIN from homeassistant.components.v2c.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None: async def test_full_flow(
"""Test we get the form.""" hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_v2c_client: AsyncMock
) -> None:
"""Test we can finish a config flow."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": SOURCE_USER}
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["errors"] == {} assert result["errors"] == {}
with patch( result = await hass.config_entries.flow.async_configure(
"pytrydan.Trydan.get_data", result["flow_id"],
return_value={}, {CONF_HOST: "1.1.1.1"},
): )
result2 = await hass.config_entries.flow.async_configure( await hass.async_block_till_done()
result["flow_id"],
{
"host": "1.1.1.1",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "EVSE 1.1.1.1" assert result["title"] == "EVSE 1.1.1.1"
assert result2["data"] == { assert result["data"] == {CONF_HOST: "1.1.1.1"}
"host": "1.1.1.1",
}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -47,41 +42,32 @@ async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
], ],
) )
async def test_form_cannot_connect( async def test_form_cannot_connect(
hass: HomeAssistant, mock_setup_entry: AsyncMock, side_effect: Exception, error: str hass: HomeAssistant,
mock_setup_entry: AsyncMock,
side_effect: Exception,
error: str,
mock_v2c_client: AsyncMock,
) -> None: ) -> None:
"""Test we handle cannot connect error.""" """Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": SOURCE_USER}
)
mock_v2c_client.get_data.side_effect = side_effect
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: "1.1.1.1"},
) )
with patch( assert result["type"] is FlowResultType.FORM
"pytrydan.Trydan.get_data", assert result["errors"] == {"base": error}
side_effect=side_effect, mock_v2c_client.get_data.side_effect = None
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
},
)
assert result2["type"] is FlowResultType.FORM result = await hass.config_entries.flow.async_configure(
assert result2["errors"] == {"base": error} result["flow_id"],
{CONF_HOST: "1.1.1.1"},
)
await hass.async_block_till_done()
with patch( assert result["type"] is FlowResultType.CREATE_ENTRY
"pytrydan.Trydan.get_data", assert result["title"] == "EVSE 1.1.1.1"
return_value={}, assert result["data"] == {CONF_HOST: "1.1.1.1"}
):
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
},
)
await hass.async_block_till_done()
assert result3["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == "EVSE 1.1.1.1"
assert result3["data"] == {
"host": "1.1.1.1",
}

View file

@ -0,0 +1,27 @@
"""Test the V2C sensor platform."""
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 init_integration
from tests.common import MockConfigEntry, snapshot_platform
async def test_sensor(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_v2c_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry_enabled_by_default: None,
) -> None:
"""Test states of the sensor."""
with patch("homeassistant.components.v2c.PLATFORMS", [Platform.SENSOR]):
await init_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)