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.""" """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.""" """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 import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.flexit_bacnet.const import DOMAIN 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.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
@pytest.fixture @pytest.fixture
async def flow_id(hass: HomeAssistant) -> str: async def flow_id(hass: HomeAssistant) -> str:
@ -22,23 +27,44 @@ async def flow_id(hass: HomeAssistant) -> str:
return result["flow_id"] return result["flow_id"]
@pytest.fixture(autouse=True) @pytest.fixture
def mock_serial_number_and_device_name(): def mock_flexit_bacnet() -> Generator[AsyncMock, None, None]:
"""Mock serial number of the device.""" """Mock data from the device."""
flexit_bacnet = AsyncMock(spec=FlexitBACnet)
with patch( with patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.serial_number", "homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet",
"0000-0001", return_value=flexit_bacnet,
), patch( ), patch(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.device_name", "homeassistant.components.flexit_bacnet.FlexitBACnet",
"Device Name", 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 @pytest.fixture
def mock_setup_entry(): def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Mock setting up a config entry.""" """Mock setting up a config entry."""
with patch( with patch(
"homeassistant.components.flexit_bacnet.async_setup_entry", return_value=True "homeassistant.components.flexit_bacnet.async_setup_entry", return_value=True
) as setup_entry_mock: ) as setup_entry_mock:
yield 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.""" """Test the Flexit Nordic (BACnet) config flow."""
import asyncio.exceptions import asyncio.exceptions
from unittest.mock import patch
from flexit_bacnet import DecodingError from flexit_bacnet import DecodingError
import pytest import pytest
from homeassistant.components.flexit_bacnet.const import DOMAIN
from homeassistant.const import CONF_DEVICE_ID, CONF_IP_ADDRESS from homeassistant.const import CONF_DEVICE_ID, CONF_IP_ADDRESS
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_form(
async def test_form(hass: HomeAssistant, flow_id: str, mock_setup_entry) -> None: hass: HomeAssistant, flow_id: str, mock_setup_entry, mock_flexit_bacnet
) -> None:
"""Test we get the form and the happy path works.""" """Test we get the form and the happy path works."""
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update" flow_id,
): {
result = await hass.config_entries.flow.async_configure( CONF_IP_ADDRESS: "1.1.1.1",
flow_id, CONF_DEVICE_ID: 2,
{ },
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.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "Device Name" 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, CONF_DEVICE_ID: 2,
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_flexit_bacnet.mock_calls) == 1
@pytest.mark.parametrize( @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( 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: ) -> None:
"""Test that we return 'cannot_connect' error when attempting to connect to an incorrect IP address. """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. The flexit_bacnet library raises asyncio.exceptions.TimeoutError in that scenario.
""" """
with patch( mock_flexit_bacnet.update.side_effect = error
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update", result = await hass.config_entries.flow.async_configure(
side_effect=error, flow_id,
): {
result = await hass.config_entries.flow.async_configure( CONF_IP_ADDRESS: "1.1.1.1",
flow_id, CONF_DEVICE_ID: 2,
{ },
CONF_IP_ADDRESS: "1.1.1.1", )
CONF_DEVICE_ID: 2,
},
)
assert result["type"] == FlowResultType.FORM assert result["type"] == FlowResultType.FORM
assert result["errors"] == {"base": message} assert result["errors"] == {"base": message}
assert len(mock_setup_entry.mock_calls) == 0 assert len(mock_setup_entry.mock_calls) == 0
# ensure that user can recover from this error # ensure that user can recover from this error
with patch( mock_flexit_bacnet.update.side_effect = None
"homeassistant.components.flexit_bacnet.config_flow.FlexitBACnet.update" result2 = await hass.config_entries.flow.async_configure(
): result["flow_id"],
result2 = await hass.config_entries.flow.async_configure( {
result["flow_id"], CONF_IP_ADDRESS: "1.1.1.1",
{ CONF_DEVICE_ID: 2,
CONF_IP_ADDRESS: "1.1.1.1", },
CONF_DEVICE_ID: 2, )
},
)
assert result2["type"] == FlowResultType.CREATE_ENTRY assert result2["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "Device Name" assert result2["title"] == "Device Name"
@ -94,27 +90,19 @@ async def test_flow_fails(
assert len(mock_setup_entry.mock_calls) == 1 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.""" """Test that we cannot add already added device."""
entry = MockConfigEntry( mock_config_entry.add_to_hass(hass)
domain=DOMAIN,
data={ result = await hass.config_entries.flow.async_configure(
flow_id,
{
CONF_IP_ADDRESS: "1.1.1.1", CONF_IP_ADDRESS: "1.1.1.1",
CONF_DEVICE_ID: 2, CONF_DEVICE_ID: 2,
}, },
unique_id="0000-0001",
) )
entry.add_to_hass(hass) await hass.async_block_till_done()
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()
assert result["type"] == FlowResultType.ABORT assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "already_configured" 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)