Add tests to flexit_bacnet integration (#108291)

* Add fixture for update method

* Mock flexit_bacnet

* Adds test for climate

* Adds snapshot testing

* Adds test for init, refactor test for config flow
This commit is contained in:
Jonas Fors Lellky 2024-01-18 14:37:43 +01:00 committed by GitHub
parent 65abbe5369
commit 7d5a672ed1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 219 additions and 65 deletions

View File

@ -1 +1,17 @@
"""Tests for the Flexit Nordic (BACnet) integration."""
from unittest.mock import patch
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_with_selected_platforms(
hass: HomeAssistant, entry: MockConfigEntry, platforms: list[Platform]
) -> None:
"""Set up the Flexit Nordic (BACnet) integration with the selected platforms."""
entry.add_to_hass(hass)
with patch("homeassistant.components.flexit_bacnet.PLATFORMS", platforms):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

View File

@ -1,13 +1,18 @@
"""Configuration for Flexit Nordic (BACnet) tests."""
from unittest.mock import patch
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
from flexit_bacnet import FlexitBACnet
import pytest
from homeassistant import config_entries
from homeassistant.components.flexit_bacnet.const import DOMAIN
from homeassistant.const import CONF_DEVICE_ID, CONF_IP_ADDRESS
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
@pytest.fixture
async def flow_id(hass: HomeAssistant) -> str:
@ -22,23 +27,44 @@ async def flow_id(hass: HomeAssistant) -> str:
return result["flow_id"]
@pytest.fixture(autouse=True)
def mock_serial_number_and_device_name():
"""Mock serial number of the device."""
@pytest.fixture
def mock_flexit_bacnet() -> Generator[AsyncMock, None, None]:
"""Mock data from the device."""
flexit_bacnet = AsyncMock(spec=FlexitBACnet)
with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.serial_number",
"0000-0001",
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet",
return_value=flexit_bacnet,
), patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.device_name",
"Device Name",
"homeassistant.components.flexit_bacnet.FlexitBACnet",
return_value=flexit_bacnet,
):
yield
flexit_bacnet.serial_number = "0000-0001"
flexit_bacnet.device_name = "Device Name"
flexit_bacnet.room_temperature = 19.0
flexit_bacnet.air_temp_setpoint_away = 18.0
flexit_bacnet.air_temp_setpoint_home = 22.0
flexit_bacnet.ventilation_mode = 4
yield flexit_bacnet
@pytest.fixture
def mock_setup_entry():
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Mock setting up a config entry."""
with patch(
"homeassistant.components.flexit_bacnet.async_setup_entry", return_value=True
) as setup_entry_mock:
yield setup_entry_mock
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Mock a config entry."""
return MockConfigEntry(
domain=DOMAIN,
data={
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
unique_id="0000-0001",
)

View File

@ -0,0 +1,73 @@
# serializer version: 1
# name: test_climate_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 19.0,
'friendly_name': 'Device Name',
'hvac_modes': list([
<HVACMode.OFF: 'off'>,
<HVACMode.FAN_ONLY: 'fan_only'>,
]),
'max_temp': 30,
'min_temp': 10,
'preset_mode': 'boost',
'preset_modes': list([
'away',
'home',
'boost',
]),
'supported_features': <ClimateEntityFeature: 17>,
'target_temp_step': 0.5,
'temperature': 22.0,
}),
'context': <ANY>,
'entity_id': 'climate.device_name',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': 'fan_only',
})
# ---
# name: test_climate_entity.1
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'hvac_modes': list([
<HVACMode.OFF: 'off'>,
<HVACMode.FAN_ONLY: 'fan_only'>,
]),
'max_temp': 30,
'min_temp': 10,
'preset_modes': list([
'away',
'home',
'boost',
]),
'target_temp_step': 0.5,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.device_name',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'flexit_bacnet',
'previous_unique_id': None,
'supported_features': <ClimateEntityFeature: 17>,
'translation_key': None,
'unique_id': '0000-0001',
'unit_of_measurement': None,
})
# ---

View File

@ -0,0 +1,27 @@
"""Tests for the Flexit Nordic (BACnet) climate entity."""
from unittest.mock import AsyncMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
import homeassistant.helpers.entity_registry as er
from tests.common import MockConfigEntry
from tests.components.flexit_bacnet import setup_with_selected_platforms
ENTITY_CLIMATE = "climate.device_name"
async def test_climate_entity(
hass: HomeAssistant,
mock_flexit_bacnet: AsyncMock,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
) -> None:
"""Test the initial parameters."""
await setup_with_selected_platforms(hass, mock_config_entry, [Platform.CLIMATE])
assert hass.states.get(ENTITY_CLIMATE) == snapshot
assert entity_registry.async_get(ENTITY_CLIMATE) == snapshot

View File

@ -1,31 +1,26 @@
"""Test the Flexit Nordic (BACnet) config flow."""
import asyncio.exceptions
from unittest.mock import patch
from flexit_bacnet import DecodingError
import pytest
from homeassistant.components.flexit_bacnet.const import DOMAIN
from homeassistant.const import CONF_DEVICE_ID, CONF_IP_ADDRESS
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_form(hass: HomeAssistant, flow_id: str, mock_setup_entry) -> None:
async def test_form(
hass: HomeAssistant, flow_id: str, mock_setup_entry, mock_flexit_bacnet
) -> None:
"""Test we get the form and the happy path works."""
with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update"
):
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "Device Name"
@ -35,6 +30,7 @@ async def test_form(hass: HomeAssistant, flow_id: str, mock_setup_entry) -> None
CONF_DEVICE_ID: 2,
}
assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_flexit_bacnet.mock_calls) == 1
@pytest.mark.parametrize(
@ -50,39 +46,39 @@ async def test_form(hass: HomeAssistant, flow_id: str, mock_setup_entry) -> None
],
)
async def test_flow_fails(
hass: HomeAssistant, flow_id: str, error: Exception, message: str, mock_setup_entry
hass: HomeAssistant,
flow_id: str,
error: Exception,
message: str,
mock_setup_entry,
mock_flexit_bacnet,
) -> None:
"""Test that we return 'cannot_connect' error when attempting to connect to an incorrect IP address.
The flexit_bacnet library raises asyncio.exceptions.TimeoutError in that scenario.
"""
with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update",
side_effect=error,
):
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
mock_flexit_bacnet.update.side_effect = error
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] == {"base": message}
assert len(mock_setup_entry.mock_calls) == 0
# ensure that user can recover from this error
with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update"
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
mock_flexit_bacnet.update.side_effect = None
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
assert result2["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "Device Name"
@ -94,27 +90,19 @@ async def test_flow_fails(
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_device_already_exist(hass: HomeAssistant, flow_id: str) -> None:
async def test_form_device_already_exist(
hass: HomeAssistant, flow_id: str, mock_flexit_bacnet, mock_config_entry
) -> None:
"""Test that we cannot add already added device."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
unique_id="0000-0001",
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update"
):
result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2,
},
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "already_configured"

View File

@ -0,0 +1,24 @@
"""Tests for the Flexit Nordic (BACnet) __init__."""
from homeassistant.components.flexit_bacnet.const import DOMAIN as FLEXIT_BACNET_DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
from tests.components.flexit_bacnet import setup_with_selected_platforms
async def test_loading_and_unloading_config_entry(
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_flexit_bacnet
) -> None:
"""Test loading and unloading a config entry."""
await setup_with_selected_platforms(hass, mock_config_entry, [Platform.CLIMATE])
assert len(hass.config_entries.async_entries(FLEXIT_BACNET_DOMAIN)) == 1
assert mock_config_entry.state == ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
assert not hass.data.get(FLEXIT_BACNET_DOMAIN)