Improve Husqvarna Automower tests (#143113)

This commit is contained in:
Thomas55555 2025-05-08 22:38:26 +02:00 committed by GitHub
parent 4c43640d0d
commit 7100481abc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 29 additions and 52 deletions

View File

@ -3,10 +3,10 @@
import asyncio import asyncio
from collections.abc import Generator from collections.abc import Generator
import time import time
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, create_autospec, patch
from aioautomower.commands import MowerCommands, WorkAreaSettings
from aioautomower.model import MowerAttributes from aioautomower.model import MowerAttributes
from aioautomower.session import AutomowerSession, MowerCommands
from aioautomower.utils import mower_list_to_dictionary_dataclass from aioautomower.utils import mower_list_to_dictionary_dataclass
from aiohttp import ClientWebSocketResponse from aiohttp import ClientWebSocketResponse
import pytest import pytest
@ -108,7 +108,9 @@ async def setup_credentials(hass: HomeAssistant) -> None:
@pytest.fixture @pytest.fixture
def mock_automower_client(values) -> Generator[AsyncMock]: def mock_automower_client(
values: dict[str, MowerAttributes],
) -> Generator[AsyncMock]:
"""Mock a Husqvarna Automower client.""" """Mock a Husqvarna Automower client."""
async def listen() -> None: async def listen() -> None:
@ -117,37 +119,21 @@ def mock_automower_client(values) -> Generator[AsyncMock]:
await listen_block.wait() await listen_block.wait()
pytest.fail("Listen was not cancelled!") pytest.fail("Listen was not cancelled!")
mock = AsyncMock(spec=AutomowerSession)
mock.auth = AsyncMock(side_effect=ClientWebSocketResponse)
mock.commands = AsyncMock(spec_set=MowerCommands)
mock.get_status.return_value = values
mock.start_listening = AsyncMock(side_effect=listen)
with patch( with patch(
"homeassistant.components.husqvarna_automower.AutomowerSession", "homeassistant.components.husqvarna_automower.AutomowerSession",
return_value=mock, autospec=True,
): spec_set=True,
yield mock ) as mock:
mock_instance = mock.return_value
mock_instance.auth = AsyncMock(side_effect=ClientWebSocketResponse)
@pytest.fixture mock_instance.get_status = AsyncMock(return_value=values)
def mock_automower_client_one_mower(values) -> Generator[AsyncMock]: mock_instance.start_listening = AsyncMock(side_effect=listen)
"""Mock a Husqvarna Automower client.""" mock_instance.commands = create_autospec(
MowerCommands, instance=True, spec_set=True
async def listen() -> None: )
"""Mock listen.""" mock_instance.commands.workarea_settings.return_value = create_autospec(
listen_block = asyncio.Event() WorkAreaSettings,
await listen_block.wait() instance=True,
pytest.fail("Listen was not cancelled!") spec_set=True,
)
mock = AsyncMock(spec=AutomowerSession) yield mock_instance
mock.auth = AsyncMock(side_effect=ClientWebSocketResponse)
mock.commands = AsyncMock(spec_set=MowerCommands)
mock.get_status.return_value = values
mock.start_listening = AsyncMock(side_effect=listen)
with patch(
"homeassistant.components.husqvarna_automower.AutomowerSession",
return_value=mock,
):
yield mock

View File

@ -64,8 +64,7 @@ async def test_button_states_and_commands(
target={ATTR_ENTITY_ID: entity_id}, target={ATTR_ENTITY_ID: entity_id},
blocking=True, blocking=True,
) )
mocked_method = getattr(mock_automower_client.commands, "error_confirm") mock_automower_client.commands.error_confirm.assert_called_once_with(TEST_MOWER_ID)
mocked_method.assert_called_once_with(TEST_MOWER_ID)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "2023-06-05T00:16:00+00:00" assert state.state == "2023-06-05T00:16:00+00:00"
@ -106,8 +105,7 @@ async def test_sync_clock(
{ATTR_ENTITY_ID: entity_id}, {ATTR_ENTITY_ID: entity_id},
blocking=True, blocking=True,
) )
mocked_method = mock_automower_client.commands.set_datetime mock_automower_client.commands.set_datetime.assert_called_once_with(TEST_MOWER_ID)
mocked_method.assert_called_once_with(TEST_MOWER_ID)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "2024-02-29T11:00:00+00:00" assert state.state == "2024-02-29T11:00:00+00:00"

View File

@ -90,9 +90,7 @@ async def test_lawn_mower_commands(
mocked_method = getattr(mock_automower_client.commands, aioautomower_command) mocked_method = getattr(mock_automower_client.commands, aioautomower_command)
mocked_method.assert_called_once_with(TEST_MOWER_ID) mocked_method.assert_called_once_with(TEST_MOWER_ID)
getattr( mocked_method.side_effect = ApiError("Test error")
mock_automower_client.commands, aioautomower_command
).side_effect = ApiError("Test error")
with pytest.raises( with pytest.raises(
HomeAssistantError, HomeAssistantError,
match="Failed to send command: Test error", match="Failed to send command: Test error",
@ -139,8 +137,7 @@ async def test_lawn_mower_service_commands(
) -> None: ) -> None:
"""Test lawn_mower commands.""" """Test lawn_mower commands."""
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
mocked_method = AsyncMock() mocked_method = getattr(mock_automower_client.commands, aioautomower_command)
setattr(mock_automower_client.commands, aioautomower_command, mocked_method)
await hass.services.async_call( await hass.services.async_call(
domain=DOMAIN, domain=DOMAIN,
service=service, service=service,
@ -150,9 +147,7 @@ async def test_lawn_mower_service_commands(
) )
mocked_method.assert_called_once_with(TEST_MOWER_ID, extra_data) mocked_method.assert_called_once_with(TEST_MOWER_ID, extra_data)
getattr( mocked_method.side_effect = ApiError("Test error")
mock_automower_client.commands, aioautomower_command
).side_effect = ApiError("Test error")
with pytest.raises( with pytest.raises(
HomeAssistantError, HomeAssistantError,
match="Failed to send command: Test error", match="Failed to send command: Test error",
@ -193,8 +188,7 @@ async def test_lawn_mower_override_work_area_command(
) -> None: ) -> None:
"""Test lawn_mower work area override commands.""" """Test lawn_mower work area override commands."""
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
mocked_method = AsyncMock() mocked_method = getattr(mock_automower_client.commands, aioautomower_command)
setattr(mock_automower_client.commands, aioautomower_command, mocked_method)
await hass.services.async_call( await hass.services.async_call(
domain=DOMAIN, domain=DOMAIN,
service=service, service=service,

View File

@ -96,7 +96,7 @@ async def test_number_workarea_commands(
service_data={"value": "75"}, service_data={"value": "75"},
blocking=True, blocking=True,
) )
assert len(mocked_method.mock_calls) == 2 assert mock_automower_client.commands.workarea_settings.call_count == 2
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")

View File

@ -133,8 +133,7 @@ async def test_stay_out_zone_switch_commands(
) )
values[TEST_MOWER_ID].stay_out_zones.zones[TEST_ZONE_ID].enabled = boolean values[TEST_MOWER_ID].stay_out_zones.zones[TEST_ZONE_ID].enabled = boolean
mock_automower_client.get_status.return_value = values mock_automower_client.get_status.return_value = values
mocked_method = AsyncMock() mocked_method = mock_automower_client.commands.switch_stay_out_zone
setattr(mock_automower_client.commands, "switch_stay_out_zone", mocked_method)
await hass.services.async_call( await hass.services.async_call(
domain=SWITCH_DOMAIN, domain=SWITCH_DOMAIN,
service=service, service=service,