From 2d6eb5c05dd95d9eb2ee1ae3de7d1e7eff69eff6 Mon Sep 17 00:00:00 2001 From: Eugene Prystupa Date: Sun, 26 Jul 2020 13:15:21 -0400 Subject: [PATCH] Refactor bond unit tests to reduce boilerplate (#38177) * Refactor bond unit tests to reduce boilerplate * Refactor bond unit tests to reduce boilerplate (PR feedback) * Refactor bond unit tests to reduce boilerplate (PR feedback, nullcontext) --- tests/components/bond/common.py | 101 ++++++++++++++++------ tests/components/bond/test_config_flow.py | 35 ++++---- tests/components/bond/test_init.py | 66 +++++++------- 3 files changed, 122 insertions(+), 80 deletions(-) diff --git a/tests/components/bond/common.py b/tests/components/bond/common.py index b4d22641204..229a9f31dfe 100644 --- a/tests/components/bond/common.py +++ b/tests/components/bond/common.py @@ -1,7 +1,8 @@ """Common methods used across tests for Bond.""" from asyncio import TimeoutError as AsyncIOTimeoutError +from contextlib import nullcontext from datetime import timedelta -from typing import Any, Dict +from typing import Any, Dict, Optional from homeassistant import core from homeassistant.components.bond.const import DOMAIN as BOND_DOMAIN @@ -12,19 +13,35 @@ from homeassistant.util import utcnow from tests.async_mock import patch from tests.common import MockConfigEntry, async_fire_time_changed -MOCK_HUB_VERSION: dict = {"bondid": "test-bond-id"} + +def patch_setup_entry(domain: str, *, enabled: bool = True): + """Patch async_setup_entry for specified domain.""" + if not enabled: + return nullcontext() + + return patch(f"homeassistant.components.bond.{domain}.async_setup_entry") async def setup_bond_entity( - hass: core.HomeAssistant, config_entry: MockConfigEntry, hub_version=None + hass: core.HomeAssistant, + config_entry: MockConfigEntry, + *, + patch_version=False, + patch_device_ids=False, + patch_platforms=False, ): """Set up Bond entity.""" - if hub_version is None: - hub_version = MOCK_HUB_VERSION - config_entry.add_to_hass(hass) - with patch("homeassistant.components.bond.Bond.version", return_value=hub_version): + with patch_bond_version(enabled=patch_version), patch_bond_device_ids( + enabled=patch_device_ids + ), patch_setup_entry("cover", enabled=patch_platforms), patch_setup_entry( + "fan", enabled=patch_platforms + ), patch_setup_entry( + "light", enabled=patch_platforms + ), patch_setup_entry( + "switch", enabled=patch_platforms + ): return await hass.config_entries.async_setup(config_entry.entry_id) @@ -36,47 +53,77 @@ async def setup_platform( props: Dict[str, Any] = None, ): """Set up the specified Bond platform.""" - if not props: - props = {} - mock_entry = MockConfigEntry( domain=BOND_DOMAIN, data={CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, ) mock_entry.add_to_hass(hass) - with patch("homeassistant.components.bond.PLATFORMS", [platform]), patch( - "homeassistant.components.bond.Bond.version", return_value=MOCK_HUB_VERSION - ), patch_bond_device_ids(return_value=[bond_device_id],), patch( - "homeassistant.components.bond.Bond.device", return_value=discovered_device - ), patch_bond_device_state( - return_value={} - ), patch( - "homeassistant.components.bond.Bond.device_properties", return_value=props - ), patch( - "homeassistant.components.bond.Bond.device_state", return_value={} - ): - assert await async_setup_component(hass, BOND_DOMAIN, {}) - await hass.async_block_till_done() + with patch("homeassistant.components.bond.PLATFORMS", [platform]): + with patch_bond_version(), patch_bond_device_ids( + return_value=[bond_device_id] + ), patch_bond_device( + return_value=discovered_device + ), patch_bond_device_state(), patch_bond_device_properties( + return_value=props + ), patch_bond_device_state(): + assert await async_setup_component(hass, BOND_DOMAIN, {}) + await hass.async_block_till_done() return mock_entry -def patch_bond_device_ids(return_value=None): - """Patch Bond API devices command.""" +def patch_bond_version(enabled: bool = True, return_value: Optional[dict] = None): + """Patch Bond API version endpoint.""" + if not enabled: + return nullcontext() + + if return_value is None: + return_value = {"bondid": "test-bond-id"} + + return patch( + "homeassistant.components.bond.Bond.version", return_value=return_value + ) + + +def patch_bond_device_ids(enabled: bool = True, return_value=None, side_effect=None): + """Patch Bond API devices endpoint.""" + if not enabled: + return nullcontext() + if return_value is None: return_value = [] return patch( - "homeassistant.components.bond.Bond.devices", return_value=return_value, + "homeassistant.components.bond.Bond.devices", + return_value=return_value, + side_effect=side_effect, + ) + + +def patch_bond_device(return_value=None): + """Patch Bond API device endpoint.""" + return patch( + "homeassistant.components.bond.Bond.device", return_value=return_value, ) def patch_bond_action(): - """Patch Bond API action command.""" + """Patch Bond API action endpoint.""" return patch("homeassistant.components.bond.Bond.action") +def patch_bond_device_properties(return_value=None): + """Patch Bond API device properties endpoint.""" + if return_value is None: + return_value = {} + + return patch( + "homeassistant.components.bond.Bond.device_properties", + return_value=return_value, + ) + + def patch_bond_device_state(return_value=None, side_effect=None): """Patch Bond API device state endpoint.""" if return_value is None: diff --git a/tests/components/bond/test_config_flow.py b/tests/components/bond/test_config_flow.py index 825215207a0..bc6609d54ec 100644 --- a/tests/components/bond/test_config_flow.py +++ b/tests/components/bond/test_config_flow.py @@ -6,6 +6,8 @@ from homeassistant import config_entries, core, setup from homeassistant.components.bond.const import DOMAIN from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST +from .common import patch_bond_device_ids + from tests.async_mock import Mock, patch @@ -18,21 +20,20 @@ async def test_form(hass: core.HomeAssistant): assert result["type"] == "form" assert result["errors"] == {} - with patch( - "homeassistant.components.bond.config_flow.Bond.devices", return_value=[], - ), patch( + with patch_bond_device_ids(), patch( "homeassistant.components.bond.async_setup", return_value=True ) as mock_setup, patch( "homeassistant.components.bond.async_setup_entry", return_value=True, ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], {CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + result["flow_id"], + {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) assert result2["type"] == "create_entry" - assert result2["title"] == "1.1.1.1" + assert result2["title"] == "some host" assert result2["data"] == { - CONF_HOST: "1.1.1.1", + CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token", } await hass.async_block_till_done() @@ -46,12 +47,12 @@ async def test_form_invalid_auth(hass: core.HomeAssistant): DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with patch( - "homeassistant.components.bond.config_flow.Bond.devices", + with patch_bond_device_ids( side_effect=ClientResponseError(Mock(), Mock(), status=401), ): result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], {CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + result["flow_id"], + {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) assert result2["type"] == "form" @@ -64,12 +65,10 @@ async def test_form_cannot_connect(hass: core.HomeAssistant): DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with patch( - "homeassistant.components.bond.config_flow.Bond.devices", - side_effect=ClientConnectionError(), - ): + with patch_bond_device_ids(side_effect=ClientConnectionError()): result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], {CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + result["flow_id"], + {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) assert result2["type"] == "form" @@ -82,12 +81,12 @@ async def test_form_unexpected_error(hass: core.HomeAssistant): DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with patch( - "homeassistant.components.bond.config_flow.Bond.devices", - side_effect=ClientResponseError(Mock(), Mock(), status=500), + with patch_bond_device_ids( + side_effect=ClientResponseError(Mock(), Mock(), status=500) ): result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], {CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + result["flow_id"], + {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) assert result2["type"] == "form" diff --git a/tests/components/bond/test_init.py b/tests/components/bond/test_init.py index 4d5fd9f4568..b75f1bbac8c 100644 --- a/tests/components/bond/test_init.py +++ b/tests/components/bond/test_init.py @@ -6,17 +6,11 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from homeassistant.setup import async_setup_component -from .common import patch_bond_device_ids, setup_bond_entity +from .common import patch_bond_version, patch_setup_entry, setup_bond_entity -from tests.async_mock import patch from tests.common import MockConfigEntry -def patch_setup_entry(domain: str): - """Patch async_setup_entry for specified domain.""" - return patch(f"homeassistant.components.bond.{domain}.async_setup_entry") - - async def test_async_setup_no_domain_config(hass: HomeAssistant): """Test setup without configuration is noop.""" result = await async_setup_component(hass, DOMAIN, {}) @@ -27,29 +21,28 @@ async def test_async_setup_no_domain_config(hass: HomeAssistant): async def test_async_setup_entry_sets_up_hub_and_supported_domains(hass: HomeAssistant): """Test that configuring entry sets up cover domain.""" config_entry = MockConfigEntry( - domain=DOMAIN, data={CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + domain=DOMAIN, data={CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) - with patch_bond_device_ids(), patch_setup_entry( - "cover" - ) as mock_cover_async_setup_entry, patch_setup_entry( - "fan" - ) as mock_fan_async_setup_entry, patch_setup_entry( - "light" - ) as mock_light_async_setup_entry, patch_setup_entry( - "switch" - ) as mock_switch_async_setup_entry: - result = await setup_bond_entity( - hass, - config_entry, - hub_version={ - "bondid": "test-bond-id", - "target": "test-model", - "fw_ver": "test-version", - }, - ) - assert result is True - await hass.async_block_till_done() + with patch_bond_version( + return_value={ + "bondid": "test-bond-id", + "target": "test-model", + "fw_ver": "test-version", + } + ): + with patch_setup_entry( + "cover" + ) as mock_cover_async_setup_entry, patch_setup_entry( + "fan" + ) as mock_fan_async_setup_entry, patch_setup_entry( + "light" + ) as mock_light_async_setup_entry, patch_setup_entry( + "switch" + ) as mock_switch_async_setup_entry: + result = await setup_bond_entity(hass, config_entry, patch_device_ids=True) + assert result is True + await hass.async_block_till_done() assert config_entry.entry_id in hass.data[DOMAIN] assert config_entry.state == ENTRY_STATE_LOADED @@ -74,15 +67,18 @@ async def test_async_setup_entry_sets_up_hub_and_supported_domains(hass: HomeAss async def test_unload_config_entry(hass: HomeAssistant): """Test that configuration entry supports unloading.""" config_entry = MockConfigEntry( - domain=DOMAIN, data={CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"}, + domain=DOMAIN, data={CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) - with patch_bond_device_ids(), patch_setup_entry("cover"), patch_setup_entry( - "fan" - ), patch_setup_entry("light"), patch_setup_entry("switch"): - result = await setup_bond_entity(hass, config_entry) - assert result is True - await hass.async_block_till_done() + result = await setup_bond_entity( + hass, + config_entry, + patch_version=True, + patch_device_ids=True, + patch_platforms=True, + ) + assert result is True + await hass.async_block_till_done() await hass.config_entries.async_unload(config_entry.entry_id) await hass.async_block_till_done()