From e9496869da79ffca49a651b39404c462f675fafc Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Wed, 2 Mar 2022 07:23:36 +0100 Subject: [PATCH] Rework mysensors test fixtures (#67331) * Reworks mysensors test fixtures * Fix missing autospecced methods --- tests/components/mysensors/conftest.py | 66 ++++++++++++++++------- tests/components/mysensors/test_init.py | 8 +-- tests/components/mysensors/test_sensor.py | 14 +++-- 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/tests/components/mysensors/conftest.py b/tests/components/mysensors/conftest.py index fe98b3f7e0a..7e38d42f011 100644 --- a/tests/components/mysensors/conftest.py +++ b/tests/components/mysensors/conftest.py @@ -4,7 +4,7 @@ from __future__ import annotations from collections.abc import AsyncGenerator, Callable, Generator import json from typing import Any -from unittest.mock import MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, patch from mysensors import BaseSyncGateway from mysensors.persistence import MySensorsJSONDecoder @@ -63,33 +63,44 @@ async def serial_transport_fixture( """Mock a serial transport.""" with patch( "mysensors.gateway_serial.AsyncTransport", autospec=True - ) as transport_class, patch("mysensors.AsyncTasks", autospec=True) as tasks_class: - tasks = tasks_class.return_value - tasks.persistence = MagicMock + ) as transport_class, patch("mysensors.task.OTAFirmware", autospec=True), patch( + "mysensors.task.load_fw", autospec=True + ), patch( + "mysensors.task.Persistence", autospec=True + ) as persistence_class: + persistence = persistence_class.return_value - mock_gateway_features(tasks, transport_class, gateway_nodes) + mock_gateway_features(persistence, transport_class, gateway_nodes) yield transport_class def mock_gateway_features( - tasks: MagicMock, transport_class: MagicMock, nodes: dict[int, Sensor] + persistence: MagicMock, transport_class: MagicMock, nodes: dict[int, Sensor] ) -> None: """Mock the gateway features.""" - async def mock_start_persistence() -> None: + async def mock_schedule_save_sensors() -> None: """Load nodes from via persistence.""" gateway = transport_class.call_args[0][0] gateway.sensors.update(nodes) - tasks.start_persistence.side_effect = mock_start_persistence + persistence.schedule_save_sensors = AsyncMock( + side_effect=mock_schedule_save_sensors + ) + # For some reason autospeccing does not recognize these methods. + persistence.safe_load_sensors = MagicMock() + persistence.save_sensors = MagicMock() - async def mock_start() -> None: + async def mock_connect() -> None: """Mock the start method.""" + transport.connect_task = MagicMock() gateway = transport_class.call_args[0][0] gateway.on_conn_made(gateway) - tasks.start.side_effect = mock_start + transport = transport_class.return_value + transport.connect_task = None + transport.connect.side_effect = mock_connect @pytest.fixture(name="transport") @@ -98,6 +109,12 @@ def transport_fixture(serial_transport: MagicMock) -> MagicMock: return serial_transport +@pytest.fixture +def transport_write(transport: MagicMock) -> MagicMock: + """Return the transport mock that accepts string messages.""" + return transport.return_value.send + + @pytest.fixture(name="serial_entry") async def serial_entry_fixture(hass: HomeAssistant) -> MockConfigEntry: """Create a config entry for a serial gateway.""" @@ -119,16 +136,28 @@ def config_entry_fixture(serial_entry: MockConfigEntry) -> MockConfigEntry: return serial_entry -@pytest.fixture -async def integration( +@pytest.fixture(name="integration") +async def integration_fixture( hass: HomeAssistant, transport: MagicMock, config_entry: MockConfigEntry -) -> AsyncGenerator[tuple[MockConfigEntry, Callable[[str], None]], None]: +) -> AsyncGenerator[MockConfigEntry, None]: """Set up the mysensors integration with a config entry.""" device = config_entry.data[CONF_DEVICE] config: dict[str, Any] = {DOMAIN: {CONF_GATEWAYS: [{CONF_DEVICE: device}]}} config_entry.add_to_hass(hass) - def receive_message(message_string: str) -> None: + with patch("homeassistant.components.mysensors.device.UPDATE_DELAY", new=0): + await async_setup_component(hass, DOMAIN, config) + await hass.async_block_till_done() + yield config_entry + + +@pytest.fixture +def receive_message( + transport: MagicMock, integration: MockConfigEntry +) -> Callable[[str], None]: + """Receive a message for the gateway.""" + + def receive_message_callback(message_string: str) -> None: """Receive a message with the transport. The message_string parameter is a string in the MySensors message format. @@ -137,14 +166,13 @@ async def integration( # node_id;child_id;command;ack;type;payload\n gateway.logic(message_string) - with patch("homeassistant.components.mysensors.device.UPDATE_DELAY", new=0): - await async_setup_component(hass, DOMAIN, config) - await hass.async_block_till_done() - yield config_entry, receive_message + return receive_message_callback @pytest.fixture(name="gateway") -def gateway_fixture(transport, integration) -> BaseSyncGateway: +def gateway_fixture( + transport: MagicMock, integration: MockConfigEntry +) -> BaseSyncGateway: """Return a setup gateway.""" return transport.call_args[0][0] diff --git a/tests/components/mysensors/test_init.py b/tests/components/mysensors/test_init.py index 6f97c312ec0..bb5d77dc7e3 100644 --- a/tests/components/mysensors/test_init.py +++ b/tests/components/mysensors/test_init.py @@ -1,8 +1,8 @@ """Test function in __init__.py.""" from __future__ import annotations -from collections.abc import Callable -from typing import Any, Awaitable +from collections.abc import Awaitable, Callable +from typing import Any from unittest.mock import patch from aiohttp import ClientWebSocketResponse @@ -359,14 +359,14 @@ async def test_import( async def test_remove_config_entry_device( hass: HomeAssistant, gps_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + integration: MockConfigEntry, gateway: BaseSyncGateway, hass_ws_client: Callable[[HomeAssistant], Awaitable[ClientWebSocketResponse]], ) -> None: """Test that a device can be removed ok.""" entity_id = "sensor.gps_sensor_1_1" node_id = 1 - config_entry, _ = integration + config_entry = integration assert await async_setup_component(hass, "config", {}) await hass.async_block_till_done() diff --git a/tests/components/mysensors/test_sensor.py b/tests/components/mysensors/test_sensor.py index 0774d480c98..45fe98b98c7 100644 --- a/tests/components/mysensors/test_sensor.py +++ b/tests/components/mysensors/test_sensor.py @@ -29,11 +29,10 @@ from tests.common import MockConfigEntry async def test_gps_sensor( hass: HomeAssistant, gps_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + receive_message: Callable[[str], None], ) -> None: """Test a gps sensor.""" entity_id = "sensor.gps_sensor_1_1" - _, receive_message = integration state = hass.states.get(entity_id) @@ -59,7 +58,7 @@ async def test_gps_sensor( async def test_power_sensor( hass: HomeAssistant, power_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + integration: MockConfigEntry, ) -> None: """Test a power sensor.""" entity_id = "sensor.power_sensor_1_1" @@ -76,7 +75,7 @@ async def test_power_sensor( async def test_energy_sensor( hass: HomeAssistant, energy_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + integration: MockConfigEntry, ) -> None: """Test an energy sensor.""" entity_id = "sensor.energy_sensor_1_1" @@ -93,7 +92,7 @@ async def test_energy_sensor( async def test_sound_sensor( hass: HomeAssistant, sound_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + integration: MockConfigEntry, ) -> None: """Test a sound sensor.""" entity_id = "sensor.sound_sensor_1_1" @@ -109,7 +108,7 @@ async def test_sound_sensor( async def test_distance_sensor( hass: HomeAssistant, distance_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + integration: MockConfigEntry, ) -> None: """Test a distance sensor.""" entity_id = "sensor.distance_sensor_1_1" @@ -129,14 +128,13 @@ async def test_distance_sensor( async def test_temperature_sensor( hass: HomeAssistant, temperature_sensor: Sensor, - integration: tuple[MockConfigEntry, Callable[[str], None]], + receive_message: Callable[[str], None], unit_system: UnitSystem, unit: str, ) -> None: """Test a temperature sensor.""" entity_id = "sensor.temperature_sensor_1_1" hass.config.units = unit_system - _, receive_message = integration temperature = "22.0" message_string = f"1;1;1;0;0;{temperature}\n"