first commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Tests for the Baidu Weather integration."""
|
||||
@@ -0,0 +1,114 @@
|
||||
"""Fixtures and mock data for Baidu Weather tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
MOCK_AK = "test_ak_key_123456"
|
||||
|
||||
MOCK_WEATHER_RESPONSE = {
|
||||
"status": 0,
|
||||
"result": {
|
||||
"location": {
|
||||
"country": "中国",
|
||||
"province": "北京市",
|
||||
"city": "北京市",
|
||||
"name": "海淀区",
|
||||
"id": "110108",
|
||||
},
|
||||
"now": {
|
||||
"temp": 25,
|
||||
"feels_like": 27,
|
||||
"rh": 60,
|
||||
"wind_class": "3级",
|
||||
"wind_dir": "南风",
|
||||
"text": "晴",
|
||||
"prec_1h": 0.0,
|
||||
"clouds": 20,
|
||||
"vis": 10000,
|
||||
"aqi": 75,
|
||||
"pm25": 35,
|
||||
"pm10": 50,
|
||||
"no2": 20,
|
||||
"so2": 5,
|
||||
"o3": 100,
|
||||
"co": 0.5,
|
||||
"uptime": "2026-02-12 14:00",
|
||||
},
|
||||
"forecasts": [
|
||||
{
|
||||
"date": "2026-02-12",
|
||||
"week": "星期四",
|
||||
"high": 28,
|
||||
"low": 18,
|
||||
"wc_day": "3级",
|
||||
"wc_night": "2级",
|
||||
"wd_day": "南风",
|
||||
"wd_night": "北风",
|
||||
"text_day": "晴",
|
||||
"text_night": "多云",
|
||||
},
|
||||
{
|
||||
"date": "2026-02-13",
|
||||
"week": "星期五",
|
||||
"high": 26,
|
||||
"low": 16,
|
||||
"wc_day": "4级",
|
||||
"wc_night": "3级",
|
||||
"wd_day": "东南风",
|
||||
"wd_night": "东风",
|
||||
"text_day": "多云",
|
||||
"text_night": "小雨",
|
||||
},
|
||||
],
|
||||
"forecast_hours": [
|
||||
{
|
||||
"text": "晴",
|
||||
"temp_fc": 25,
|
||||
"wind_class": "3级",
|
||||
"wind_dir": "南风",
|
||||
"rh": 60,
|
||||
"prec_1h": 0.0,
|
||||
"clouds": 20,
|
||||
"data_time": "2026-02-12 15:00",
|
||||
},
|
||||
{
|
||||
"text": "多云",
|
||||
"temp_fc": 24,
|
||||
"wind_class": "2级",
|
||||
"wind_dir": "南风",
|
||||
"rh": 65,
|
||||
"prec_1h": 0.0,
|
||||
"clouds": 40,
|
||||
"data_time": "2026-02-12 16:00",
|
||||
},
|
||||
],
|
||||
"alerts": [
|
||||
{
|
||||
"type": "大风",
|
||||
"level": "蓝色",
|
||||
"title": "北京市气象台发布大风蓝色预警",
|
||||
"desc": "预计未来24小时将出现5-6级大风。",
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "紫外线指数",
|
||||
"brief": "强",
|
||||
"detail": "紫外线辐射强,建议涂擦SPF20左右的防晒霜。",
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
MOCK_DISTRICT_CSV = """district_id,province,city,district
|
||||
110100,北京市,北京市,东城区
|
||||
110101,北京市,北京市,西城区
|
||||
110108,北京市,北京市,海淀区
|
||||
310100,上海市,上海市,黄浦区
|
||||
310101,上海市,上海市,徐汇区
|
||||
"""
|
||||
@@ -0,0 +1,108 @@
|
||||
"""Tests for Baidu Weather API client."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import aiohttp
|
||||
import pytest
|
||||
|
||||
from custom_components.hass_weather_baidu.api import (
|
||||
BaiduWeatherApiClient,
|
||||
BaiduWeatherApiError,
|
||||
BaiduWeatherAuthError,
|
||||
BaiduWeatherConnectionError,
|
||||
async_fetch_district_data,
|
||||
)
|
||||
|
||||
from .conftest import MOCK_AK, MOCK_DISTRICT_CSV, MOCK_WEATHER_RESPONSE
|
||||
|
||||
|
||||
class TestBaiduWeatherApiClient:
|
||||
"""Test BaiduWeatherApiClient."""
|
||||
|
||||
async def test_get_weather_by_district_success(self) -> None:
|
||||
"""Test successful weather fetch by district ID."""
|
||||
session = MagicMock(spec=aiohttp.ClientSession)
|
||||
mock_response = AsyncMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.json = AsyncMock(return_value=MOCK_WEATHER_RESPONSE)
|
||||
session.get = AsyncMock(return_value=mock_response)
|
||||
session.get.return_value.__aenter__ = AsyncMock(
|
||||
return_value=mock_response
|
||||
)
|
||||
session.get.return_value.__aexit__ = AsyncMock(return_value=False)
|
||||
|
||||
client = BaiduWeatherApiClient(session=session, ak=MOCK_AK)
|
||||
|
||||
with patch("asyncio.timeout"):
|
||||
result = await client.async_get_weather_by_district("110108")
|
||||
|
||||
assert result is not None
|
||||
assert "now" in result or "location" in result
|
||||
|
||||
async def test_get_weather_auth_error(self) -> None:
|
||||
"""Test auth error handling."""
|
||||
session = MagicMock(spec=aiohttp.ClientSession)
|
||||
error_response = {"status": 211, "message": "AK无效"}
|
||||
mock_response = AsyncMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.json = AsyncMock(return_value=error_response)
|
||||
session.get = AsyncMock(return_value=mock_response)
|
||||
|
||||
client = BaiduWeatherApiClient(session=session, ak="invalid_ak")
|
||||
|
||||
with pytest.raises(BaiduWeatherAuthError):
|
||||
with patch("asyncio.timeout"):
|
||||
await client.async_get_weather_by_district("110108")
|
||||
|
||||
async def test_clean_abnormal_values(self) -> None:
|
||||
"""Test that abnormal values are cleaned."""
|
||||
session = MagicMock(spec=aiohttp.ClientSession)
|
||||
response_data = {
|
||||
"status": 0,
|
||||
"result": {
|
||||
"now": {
|
||||
"temp": 25,
|
||||
"pressure": 999999,
|
||||
"wind_class": "暂无",
|
||||
}
|
||||
},
|
||||
}
|
||||
mock_response = AsyncMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.json = AsyncMock(return_value=response_data)
|
||||
session.get = AsyncMock(return_value=mock_response)
|
||||
|
||||
client = BaiduWeatherApiClient(session=session, ak=MOCK_AK)
|
||||
|
||||
with patch("asyncio.timeout"):
|
||||
result = await client.async_get_weather_by_district("110108")
|
||||
|
||||
assert result["now"]["temp"] == 25
|
||||
assert result["now"]["pressure"] is None
|
||||
assert result["now"]["wind_class"] is None
|
||||
|
||||
|
||||
class TestAsyncFetchDistrictData:
|
||||
"""Test district data fetching."""
|
||||
|
||||
async def test_parse_district_csv(self) -> None:
|
||||
"""Test CSV parsing returns correct structure."""
|
||||
session = MagicMock(spec=aiohttp.ClientSession)
|
||||
mock_response = AsyncMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.text = AsyncMock(return_value=MOCK_DISTRICT_CSV)
|
||||
session.get = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("asyncio.timeout"):
|
||||
result = await async_fetch_district_data(session)
|
||||
|
||||
assert "北京市" in result
|
||||
assert "北京市" in result["北京市"]
|
||||
assert "海淀区" in result["北京市"]["北京市"]
|
||||
assert result["北京市"]["北京市"]["海淀区"] == "110108"
|
||||
|
||||
assert "上海市" in result
|
||||
assert "黄浦区" in result["上海市"]["上海市"]
|
||||
Reference in New Issue
Block a user