1
mirror of https://github.com/home-assistant/core synced 2024-09-06 10:29:55 +02:00

Cleanup weather test (#103090)

* Cleanup weather test

* rename

* Clean off not used MockWeatherCompat

* conftest

* more cleanup

* Fin mod tests

* fix others
This commit is contained in:
G Johansson 2023-11-03 05:53:38 +01:00 committed by GitHub
parent 379c75ea1b
commit 12e1acfcfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 547 additions and 662 deletions

View File

@ -1,14 +1,71 @@
"""The tests for Weather platforms.""" """The tests for Weather platforms."""
from homeassistant.components.weather import ATTR_CONDITION_SUNNY from typing import Any
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.components.weather import (
ATTR_CONDITION_SUNNY,
ATTR_FORECAST_CLOUD_COVERAGE,
ATTR_FORECAST_HUMIDITY,
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
ATTR_FORECAST_NATIVE_DEW_POINT,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_UV_INDEX,
ATTR_FORECAST_WIND_BEARING,
DOMAIN,
Forecast,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from tests.common import (
MockConfigEntry,
MockModule,
MockPlatform,
mock_integration,
mock_platform,
)
from tests.testing_config.custom_components.test import weather as WeatherPlatform from tests.testing_config.custom_components.test import weather as WeatherPlatform
async def create_entity(hass: HomeAssistant, **kwargs): class MockWeatherTest(WeatherPlatform.MockWeather):
"""Mock weather class."""
def __init__(self, **values: Any) -> None:
"""Initialize."""
super().__init__(**values)
self.forecast_list: list[Forecast] | None = [
{
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
ATTR_FORECAST_NATIVE_APPARENT_TEMP: self.native_apparent_temperature,
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
ATTR_FORECAST_NATIVE_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_CLOUD_COVERAGE: self.cloud_coverage,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: self.native_wind_gust_speed,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,
ATTR_FORECAST_UV_INDEX: self.uv_index,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._values.get(
"native_precipitation"
),
ATTR_FORECAST_HUMIDITY: self.humidity,
}
]
async def create_entity(
hass: HomeAssistant,
mock_weather: WeatherPlatform.MockWeather,
manifest_extra: dict[str, Any] | None,
**kwargs,
) -> WeatherPlatform.MockWeather:
"""Create the weather entity to run tests on.""" """Create the weather entity to run tests on."""
kwargs = { kwargs = {
"native_temperature": None, "native_temperature": None,
@ -16,17 +73,47 @@ async def create_entity(hass: HomeAssistant, **kwargs):
"is_daytime": True, "is_daytime": True,
**kwargs, **kwargs,
} }
platform: WeatherPlatform = getattr(hass.components, "test.weather")
platform.init(empty=True) weather_entity = mock_weather(
platform.ENTITIES.append( name="Testing",
platform.MockWeatherMockForecast( entity_id="weather.testing",
name="Test", condition=ATTR_CONDITION_SUNNY, **kwargs condition=ATTR_CONDITION_SUNNY,
) **kwargs,
) )
entity0 = platform.ENTITIES[0] async def async_setup_entry_init(
assert await async_setup_component( hass: HomeAssistant, config_entry: ConfigEntry
hass, "weather", {"weather": {"platform": "test"}} ) -> bool:
"""Set up test config entry."""
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
return True
async def async_setup_entry_weather_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up test weather platform via config entry."""
async_add_entities([weather_entity])
mock_integration(
hass,
MockModule(
"test",
async_setup_entry=async_setup_entry_init,
partial_manifest=manifest_extra,
),
built_in=False,
) )
mock_platform(
hass,
"test.weather",
MockPlatform(async_setup_entry=async_setup_entry_weather_platform),
)
config_entry = MockConfigEntry(domain="test")
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
return entity0
return weather_entity

View File

@ -0,0 +1,22 @@
"""Fixtures for Weather platform tests."""
from collections.abc import Generator
import pytest
from homeassistant.config_entries import ConfigFlow
from homeassistant.core import HomeAssistant
from tests.common import mock_config_flow, mock_platform
class MockFlow(ConfigFlow):
"""Test flow."""
@pytest.fixture
def config_flow_fixture(hass: HomeAssistant) -> Generator[None, None, None]:
"""Mock config flow."""
mock_platform(hass, "test.config_flow")
with mock_config_flow("test", MockFlow):
yield

File diff suppressed because it is too large Load Diff

View File

@ -5,56 +5,43 @@ from datetime import timedelta
from homeassistant.components.recorder import Recorder from homeassistant.components.recorder import Recorder
from homeassistant.components.recorder.history import get_significant_states from homeassistant.components.recorder.history import get_significant_states
from homeassistant.components.weather import ATTR_CONDITION_SUNNY, ATTR_FORECAST from homeassistant.components.weather import ATTR_FORECAST, Forecast
from homeassistant.const import UnitOfTemperature from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from homeassistant.util.unit_system import METRIC_SYSTEM from homeassistant.util.unit_system import METRIC_SYSTEM
from . import MockWeatherTest, create_entity
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
from tests.components.recorder.common import async_wait_recording_done from tests.components.recorder.common import async_wait_recording_done
from tests.testing_config.custom_components.test import weather as WeatherPlatform
async def create_entity(hass: HomeAssistant, **kwargs):
"""Create the weather entity to run tests on."""
kwargs = {
"native_temperature": None,
"native_temperature_unit": None,
"is_daytime": True,
**kwargs,
}
platform: WeatherPlatform = getattr(hass.components, "test.weather")
platform.init(empty=True)
platform.ENTITIES.append(
platform.MockWeatherMockForecast(
name="Test", condition=ATTR_CONDITION_SUNNY, **kwargs
)
)
entity0 = platform.ENTITIES[0]
assert await async_setup_component(
hass, "weather", {"weather": {"platform": "test"}}
)
await hass.async_block_till_done()
return entity0
async def test_exclude_attributes( async def test_exclude_attributes(
recorder_mock: Recorder, hass: HomeAssistant, enable_custom_integrations: None recorder_mock: Recorder,
hass: HomeAssistant,
config_flow_fixture: None,
) -> None: ) -> None:
"""Test weather attributes to be excluded.""" """Test weather attributes to be excluded."""
now = dt_util.utcnow() now = dt_util.utcnow()
entity0 = await create_entity(
hass, class MockWeatherMockForecast(MockWeatherTest):
native_temperature=38, """Mock weather class with mocked legacy forecast."""
native_temperature_unit=UnitOfTemperature.CELSIUS,
) @property
def forecast(self) -> list[Forecast] | None:
"""Return the forecast."""
return self.forecast_list
kwargs = {
"native_temperature": 38,
"native_temperature_unit": UnitOfTemperature.CELSIUS,
}
weather_entity = await create_entity(hass, MockWeatherMockForecast, None, **kwargs)
hass.config.units = METRIC_SYSTEM hass.config.units = METRIC_SYSTEM
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(entity0.entity_id) state = hass.states.get(weather_entity.entity_id)
assert state.attributes[ATTR_FORECAST] assert state.attributes[ATTR_FORECAST]
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -1,11 +1,11 @@
"""Test the weather websocket API.""" """Test the weather websocket API."""
from homeassistant.components.weather import WeatherEntityFeature from homeassistant.components.weather import Forecast, WeatherEntityFeature
from homeassistant.components.weather.const import DOMAIN from homeassistant.components.weather.const import DOMAIN
from homeassistant.const import UnitOfTemperature from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from . import create_entity from . import MockWeatherTest, create_entity
from tests.typing import WebSocketGenerator from tests.typing import WebSocketGenerator
@ -40,16 +40,23 @@ async def test_device_class_units(
async def test_subscribe_forecast( async def test_subscribe_forecast(
hass: HomeAssistant, hass: HomeAssistant,
hass_ws_client: WebSocketGenerator, hass_ws_client: WebSocketGenerator,
enable_custom_integrations: None, config_flow_fixture: None,
) -> None: ) -> None:
"""Test multiple forecast.""" """Test multiple forecast."""
entity0 = await create_entity( class MockWeatherMockForecast(MockWeatherTest):
hass, """Mock weather class."""
native_temperature=38,
native_temperature_unit=UnitOfTemperature.CELSIUS, async def async_forecast_daily(self) -> list[Forecast] | None:
supported_features=WeatherEntityFeature.FORECAST_DAILY, """Return the forecast_daily."""
) return self.forecast_list
kwargs = {
"native_temperature": 38,
"native_temperature_unit": UnitOfTemperature.CELSIUS,
"supported_features": WeatherEntityFeature.FORECAST_DAILY,
}
weather_entity = await create_entity(hass, MockWeatherMockForecast, None, **kwargs)
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
@ -57,7 +64,7 @@ async def test_subscribe_forecast(
{ {
"type": "weather/subscribe_forecast", "type": "weather/subscribe_forecast",
"forecast_type": "daily", "forecast_type": "daily",
"entity_id": entity0.entity_id, "entity_id": weather_entity.entity_id,
} }
) )
msg = await client.receive_json() msg = await client.receive_json()
@ -82,16 +89,16 @@ async def test_subscribe_forecast(
], ],
} }
await entity0.async_update_listeners(None) await weather_entity.async_update_listeners(None)
msg = await client.receive_json() msg = await client.receive_json()
assert msg["event"] == forecast assert msg["event"] == forecast
await entity0.async_update_listeners(["daily"]) await weather_entity.async_update_listeners(["daily"])
msg = await client.receive_json() msg = await client.receive_json()
assert msg["event"] == forecast assert msg["event"] == forecast
entity0.forecast_list = None weather_entity.forecast_list = None
await entity0.async_update_listeners(None) await weather_entity.async_update_listeners(None)
msg = await client.receive_json() msg = await client.receive_json()
assert msg["event"] == {"type": "daily", "forecast": None} assert msg["event"] == {"type": "daily", "forecast": None}
@ -99,7 +106,6 @@ async def test_subscribe_forecast(
async def test_subscribe_forecast_unknown_entity( async def test_subscribe_forecast_unknown_entity(
hass: HomeAssistant, hass: HomeAssistant,
hass_ws_client: WebSocketGenerator, hass_ws_client: WebSocketGenerator,
enable_custom_integrations: None,
) -> None: ) -> None:
"""Test multiple forecast.""" """Test multiple forecast."""
@ -125,23 +131,25 @@ async def test_subscribe_forecast_unknown_entity(
async def test_subscribe_forecast_unsupported( async def test_subscribe_forecast_unsupported(
hass: HomeAssistant, hass: HomeAssistant,
hass_ws_client: WebSocketGenerator, hass_ws_client: WebSocketGenerator,
enable_custom_integrations: None, config_flow_fixture: None,
) -> None: ) -> None:
"""Test multiple forecast.""" """Test multiple forecast."""
entity0 = await create_entity( class MockWeatherMock(MockWeatherTest):
hass, """Mock weather class."""
native_temperature=38,
native_temperature_unit=UnitOfTemperature.CELSIUS,
)
kwargs = {
"native_temperature": 38,
"native_temperature_unit": UnitOfTemperature.CELSIUS,
}
weather_entity = await create_entity(hass, MockWeatherMock, None, **kwargs)
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
await client.send_json_auto_id( await client.send_json_auto_id(
{ {
"type": "weather/subscribe_forecast", "type": "weather/subscribe_forecast",
"forecast_type": "daily", "forecast_type": "daily",
"entity_id": entity0.entity_id, "entity_id": weather_entity.entity_id,
} }
) )
msg = await client.receive_json() msg = await client.receive_json()

View File

@ -23,6 +23,7 @@ from homeassistant.components.weather import (
Forecast, Forecast,
WeatherEntity, WeatherEntity,
) )
from homeassistant.core import HomeAssistant
from tests.common import MockEntity from tests.common import MockEntity
@ -36,7 +37,7 @@ def init(empty=False):
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities_callback, discovery_info=None hass: HomeAssistant, config, async_add_entities_callback, discovery_info=None
): ):
"""Return mock entities.""" """Return mock entities."""
async_add_entities_callback(ENTITIES) async_add_entities_callback(ENTITIES)
@ -135,79 +136,10 @@ class MockWeather(MockEntity, WeatherEntity):
"""Return the current condition.""" """Return the current condition."""
return self._handle("condition") return self._handle("condition")
class MockWeatherCompat(MockEntity, WeatherEntity):
"""Mock weather class for backwards compatibility check."""
@property @property
def temperature(self) -> float | None: def precision(self) -> float:
"""Return the platform temperature.""" """Return the precision of the temperature."""
return self._handle("temperature") return self._handle("precision")
@property
def temperature_unit(self) -> str | None:
"""Return the unit of measurement for temperature."""
return self._handle("temperature_unit")
@property
def pressure(self) -> float | None:
"""Return the pressure."""
return self._handle("pressure")
@property
def pressure_unit(self) -> str | None:
"""Return the unit of measurement for pressure."""
return self._handle("pressure_unit")
@property
def humidity(self) -> float | None:
"""Return the humidity."""
return self._handle("humidity")
@property
def wind_speed(self) -> float | None:
"""Return the wind speed."""
return self._handle("wind_speed")
@property
def wind_speed_unit(self) -> str | None:
"""Return the unit of measurement for wind speed."""
return self._handle("wind_speed_unit")
@property
def wind_bearing(self) -> float | str | None:
"""Return the wind bearing."""
return self._handle("wind_bearing")
@property
def ozone(self) -> float | None:
"""Return the ozone level."""
return self._handle("ozone")
@property
def visibility(self) -> float | None:
"""Return the visibility."""
return self._handle("visibility")
@property
def visibility_unit(self) -> str | None:
"""Return the unit of measurement for visibility."""
return self._handle("visibility_unit")
@property
def forecast(self) -> list[Forecast] | None:
"""Return the forecast."""
return self._handle("forecast")
@property
def precipitation_unit(self) -> str | None:
"""Return the unit of measurement for accumulated precipitation."""
return self._handle("precipitation_unit")
@property
def condition(self) -> str | None:
"""Return the current condition."""
return self._handle("condition")
class MockWeatherMockForecast(MockWeather): class MockWeatherMockForecast(MockWeather):

View File

@ -1 +0,0 @@
"""An integration with Weather platform."""

View File

@ -1,9 +0,0 @@
{
"domain": "test_weather",
"name": "Test Weather",
"documentation": "http://example.com",
"requirements": [],
"dependencies": [],
"codeowners": [],
"version": "1.2.3"
}

View File

@ -1,210 +0,0 @@
"""Provide a mock weather platform.
Call init before using it in your tests to ensure clean test data.
"""
from __future__ import annotations
from typing import Any
from homeassistant.components.weather import (
ATTR_FORECAST_CLOUD_COVERAGE,
ATTR_FORECAST_HUMIDITY,
ATTR_FORECAST_IS_DAYTIME,
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
ATTR_FORECAST_NATIVE_DEW_POINT,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_UV_INDEX,
ATTR_FORECAST_WIND_BEARING,
Forecast,
WeatherEntity,
)
from tests.common import MockEntity
ENTITIES = []
def init(empty=False):
"""Initialize the platform with entities."""
global ENTITIES
ENTITIES = [] if empty else [MockWeatherMockForecast()]
async def async_setup_platform(
hass, config, async_add_entities_callback, discovery_info=None
):
"""Return mock entities."""
async_add_entities_callback(ENTITIES)
class MockWeatherMockForecast(MockEntity, WeatherEntity):
"""Mock weather class."""
def __init__(self, **values: Any) -> None:
"""Initialize."""
super().__init__(**values)
self.forecast_list: list[Forecast] | None = [
{
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
ATTR_FORECAST_NATIVE_APPARENT_TEMP: self.native_apparent_temperature,
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
ATTR_FORECAST_NATIVE_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_CLOUD_COVERAGE: self.cloud_coverage,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: self.native_wind_gust_speed,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,
ATTR_FORECAST_UV_INDEX: self.uv_index,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._values.get(
"native_precipitation"
),
ATTR_FORECAST_HUMIDITY: self.humidity,
}
]
@property
def forecast(self) -> list[Forecast] | None:
"""Return the forecast."""
return self.forecast_list
async def async_forecast_daily(self) -> list[Forecast] | None:
"""Return the forecast_daily."""
return self.forecast_list
async def async_forecast_twice_daily(self) -> list[Forecast] | None:
"""Return the forecast_twice_daily."""
return [
{
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
ATTR_FORECAST_NATIVE_APPARENT_TEMP: self.native_apparent_temperature,
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
ATTR_FORECAST_NATIVE_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_CLOUD_COVERAGE: self.cloud_coverage,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: self.native_wind_gust_speed,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,
ATTR_FORECAST_UV_INDEX: self.uv_index,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._values.get(
"native_precipitation"
),
ATTR_FORECAST_HUMIDITY: self.humidity,
ATTR_FORECAST_IS_DAYTIME: self._values.get("is_daytime"),
}
]
async def async_forecast_hourly(self) -> list[Forecast] | None:
"""Return the forecast_hourly."""
return [
{
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
ATTR_FORECAST_NATIVE_APPARENT_TEMP: self.native_apparent_temperature,
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
ATTR_FORECAST_NATIVE_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_CLOUD_COVERAGE: self.cloud_coverage,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: self.native_wind_gust_speed,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,
ATTR_FORECAST_UV_INDEX: self.uv_index,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._values.get(
"native_precipitation"
),
ATTR_FORECAST_HUMIDITY: self.humidity,
}
]
@property
def native_temperature(self) -> float | None:
"""Return the platform temperature."""
return self._handle("native_temperature")
@property
def native_apparent_temperature(self) -> float | None:
"""Return the platform apparent temperature."""
return self._handle("native_apparent_temperature")
@property
def native_dew_point(self) -> float | None:
"""Return the platform dewpoint temperature."""
return self._handle("native_dew_point")
@property
def native_temperature_unit(self) -> str | None:
"""Return the unit of measurement for temperature."""
return self._handle("native_temperature_unit")
@property
def native_pressure(self) -> float | None:
"""Return the pressure."""
return self._handle("native_pressure")
@property
def native_pressure_unit(self) -> str | None:
"""Return the unit of measurement for pressure."""
return self._handle("native_pressure_unit")
@property
def humidity(self) -> float | None:
"""Return the humidity."""
return self._handle("humidity")
@property
def native_wind_gust_speed(self) -> float | None:
"""Return the wind speed."""
return self._handle("native_wind_gust_speed")
@property
def native_wind_speed(self) -> float | None:
"""Return the wind speed."""
return self._handle("native_wind_speed")
@property
def native_wind_speed_unit(self) -> str | None:
"""Return the unit of measurement for wind speed."""
return self._handle("native_wind_speed_unit")
@property
def wind_bearing(self) -> float | str | None:
"""Return the wind bearing."""
return self._handle("wind_bearing")
@property
def ozone(self) -> float | None:
"""Return the ozone level."""
return self._handle("ozone")
@property
def cloud_coverage(self) -> float | None:
"""Return the cloud coverage in %."""
return self._handle("cloud_coverage")
@property
def uv_index(self) -> float | None:
"""Return the UV index."""
return self._handle("uv_index")
@property
def native_visibility(self) -> float | None:
"""Return the visibility."""
return self._handle("native_visibility")
@property
def native_visibility_unit(self) -> str | None:
"""Return the unit of measurement for visibility."""
return self._handle("native_visibility_unit")
@property
def native_precipitation_unit(self) -> str | None:
"""Return the native unit of measurement for accumulated precipitation."""
return self._handle("native_precipitation_unit")
@property
def condition(self) -> str | None:
"""Return the current condition."""
return self._handle("condition")