Refactor airq tests to mock the API class in a fixture (#149712)

This commit is contained in:
Renat Sibgatulin
2025-08-09 00:01:39 +02:00
committed by GitHub
parent b41a9575af
commit c0bef51563
3 changed files with 68 additions and 52 deletions

View File

@@ -5,6 +5,8 @@ from unittest.mock import AsyncMock, patch
import pytest
from .common import TEST_DEVICE_DATA, TEST_DEVICE_INFO
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
@@ -13,3 +15,27 @@ def mock_setup_entry() -> Generator[AsyncMock]:
"homeassistant.components.airq.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture
def mock_airq():
"""Mock the aioairq.AirQ object.
The integration imports it in two places: in coordinator and config_flow.
"""
with (
patch(
"homeassistant.components.airq.coordinator.AirQ",
autospec=True,
) as mock_airq_class,
patch(
"homeassistant.components.airq.config_flow.AirQ",
new=mock_airq_class,
),
):
airq = mock_airq_class.return_value
# Pre-configure default mock values for setup
airq.fetch_device_info = AsyncMock(return_value=TEST_DEVICE_INFO)
airq.get_latest_data = AsyncMock(return_value=TEST_DEVICE_DATA)
yield airq

View File

@@ -1,7 +1,7 @@
"""Test the air-Q config flow."""
import logging
from unittest.mock import patch
from unittest.mock import AsyncMock
from aioairq import InvalidAuth
from aiohttp.client_exceptions import ClientConnectionError
@@ -29,7 +29,11 @@ DEFAULT_OPTIONS = {
}
async def test_form(hass: HomeAssistant, caplog: pytest.LogCaptureFixture) -> None:
async def test_form(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mock_airq: AsyncMock,
) -> None:
"""Test we get the form."""
caplog.set_level(logging.DEBUG)
result = await hass.config_entries.flow.async_init(
@@ -38,10 +42,6 @@ async def test_form(hass: HomeAssistant, caplog: pytest.LogCaptureFixture) -> No
assert result["type"] is FlowResultType.FORM
assert result["errors"] is None
with (
patch("aioairq.AirQ.validate"),
patch("aioairq.AirQ.fetch_device_info", return_value=TEST_DEVICE_INFO),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
TEST_USER_DATA,
@@ -54,13 +54,13 @@ async def test_form(hass: HomeAssistant, caplog: pytest.LogCaptureFixture) -> No
assert result2["data"] == TEST_USER_DATA
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
async def test_form_invalid_auth(hass: HomeAssistant, mock_airq: AsyncMock) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch("aioairq.AirQ.validate", side_effect=InvalidAuth):
mock_airq.validate.side_effect = InvalidAuth
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], TEST_USER_DATA | {CONF_PASSWORD: "wrong_password"}
)
@@ -69,13 +69,13 @@ async def test_form_invalid_auth(hass: HomeAssistant) -> None:
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
async def test_form_cannot_connect(hass: HomeAssistant, mock_airq: AsyncMock) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch("aioairq.AirQ.validate", side_effect=ClientConnectionError):
mock_airq.validate.side_effect = ClientConnectionError
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], TEST_USER_DATA
)
@@ -84,7 +84,7 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None:
assert result2["errors"] == {"base": "cannot_connect"}
async def test_duplicate_error(hass: HomeAssistant) -> None:
async def test_duplicate_error(hass: HomeAssistant, mock_airq: AsyncMock) -> None:
"""Test that errors are shown when duplicates are added."""
MockConfigEntry(
data=TEST_USER_DATA,
@@ -96,10 +96,6 @@ async def test_duplicate_error(hass: HomeAssistant) -> None:
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with (
patch("aioairq.AirQ.validate"),
patch("aioairq.AirQ.fetch_device_info", return_value=TEST_DEVICE_INFO),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], TEST_USER_DATA
)

View File

@@ -1,7 +1,7 @@
"""Test the air-Q coordinator."""
import logging
from unittest.mock import patch
from unittest.mock import AsyncMock
import pytest
@@ -32,7 +32,9 @@ STATUS_WARMUP = {
async def test_logging_in_coordinator_first_update_data(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mock_airq: AsyncMock,
) -> None:
"""Test that the first AirQCoordinator._async_update_data call logs necessary setup.
@@ -48,10 +50,6 @@ async def test_logging_in_coordinator_first_update_data(
assert "name" not in coordinator.device_info
# First call: fetch missing device info
with (
patch("aioairq.AirQ.fetch_device_info", return_value=TEST_DEVICE_INFO),
patch("aioairq.AirQ.get_latest_data", return_value=TEST_DEVICE_DATA),
):
await coordinator._async_update_data()
# check that the missing name is logged...
@@ -71,7 +69,9 @@ async def test_logging_in_coordinator_first_update_data(
async def test_logging_in_coordinator_subsequent_update_data(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mock_airq: AsyncMock,
) -> None:
"""Test that the second AirQCoordinator._async_update_data call has nothing to log.
@@ -83,10 +83,6 @@ async def test_logging_in_coordinator_subsequent_update_data(
coordinator = AirQCoordinator(hass, MOCKED_ENTRY)
coordinator.device_info.update(DeviceInfo(**TEST_DEVICE_INFO))
with (
patch("aioairq.AirQ.fetch_device_info", return_value=TEST_DEVICE_INFO),
patch("aioairq.AirQ.get_latest_data", return_value=TEST_DEVICE_DATA),
):
await coordinator._async_update_data()
# check that the name _is not_ missing
assert "name" in coordinator.device_info
@@ -102,18 +98,16 @@ async def test_logging_in_coordinator_subsequent_update_data(
async def test_logging_when_warming_up_sensor_present(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mock_airq: AsyncMock,
) -> None:
"""Test that warming up sensors are logged."""
caplog.set_level(logging.DEBUG)
coordinator = AirQCoordinator(hass, MOCKED_ENTRY)
with (
patch("aioairq.AirQ.fetch_device_info", return_value=TEST_DEVICE_INFO),
patch(
"aioairq.AirQ.get_latest_data",
return_value=TEST_DEVICE_DATA | {"Status": STATUS_WARMUP},
),
):
mock_airq.get_latest_data.return_value = TEST_DEVICE_DATA | {
"Status": STATUS_WARMUP
}
await coordinator._async_update_data()
assert (
f"Following sensors are still warming up: {set(STATUS_WARMUP.keys())}"