Files
shaguabijia-app-server/tests/test_meituan_city.py
guke 7b6756f936 feat(meituan-cps): 经纬度→城市离线反查 + rec/销量最高按城市过滤 (#116)
## 主要功能
新增离线「经纬度 → 美团 cityId」反查,让 `rec`(智能推荐)与 `top-sales`(销量最高)从离线库只返**同城券**(此前会混返异地券)。

- `app/utils/geo.py` + `app/utils/meituan_city.py`:坐标 → 美团 `city_id`(reverse_geocoder 离线反查,零网络)。
- `feed?tab=rec` / `/top-sales`:按 `city_id` 过滤;解析不出 / 老客户端不带坐标 → 降级返空。
- `top-sales` 与 `rec` 一致置空库内距离(相对城市默认点、对用户无意义)。

---------

Co-authored-by: guke <guke@autohome.com.cn>
Reviewed-on: #116
Co-authored-by: guke <guke@wonderable.ai>
Co-committed-by: guke <guke@wonderable.ai>
2026-07-05 09:31:53 +08:00

65 lines
2.7 KiB
Python

"""app.utils.meituan_city.get_meituan_city 经纬度→美团城市 反查测试。
覆盖 get_meituan_city 的分支(test_geo.py 只覆盖底层 get_city):
- 主要城市 → 正确省份 + 非空 city_id(+ 直辖市/省会命中中文城市名)
- 非中国境内坐标 → city_id 为空(接口据此降级返空)
- 返回 dict 结构 / 类型
- 坐标量化(~1km)后近点命中同一缓存结果
- 返回的是缓存副本(调用方原地修改不污染缓存)
"""
from __future__ import annotations
import pytest
from app.utils.meituan_city import get_meituan_city
# (标签, 纬度, 经度, 期望省份名, 期望城市名)
_CASES = [
("北京", 39.9042, 116.4074, "北京市", "北京市"),
("上海", 31.2304, 121.4737, "上海市", "上海市"),
("广州", 23.1291, 113.2644, "广东省", "广州市"),
("深圳", 22.5431, 114.0579, "广东省", "深圳市"),
("成都", 30.5728, 104.0668, "四川省", "成都市"),
("杭州", 30.2741, 120.1551, "浙江省", "杭州市"),
("武汉", 30.5928, 114.3055, "湖北省", "武汉市"),
("郑州", 34.7466, 113.6253, "河南省", "郑州市"),
("厦门", 24.4798, 118.0894, "福建省", "厦门市"),
("青岛", 36.0671, 120.3826, "山东省", "青岛市"),
]
@pytest.mark.parametrize("label,lat,lon,exp_province,exp_city", _CASES)
def test_major_city_resolves(label: str, lat: float, lon: float,
exp_province: str, exp_city: str) -> None:
r = get_meituan_city(lat, lon)
assert r["province_name"] == exp_province, f"{label}: province {r!r}"
assert r["city_name"] == exp_city, f"{label}: city {r!r}"
assert r["city_id"], f"{label}: city_id 不应为空 {r!r}"
def test_non_china_returns_empty_city_id() -> None:
"""境外/远洋坐标 → city_id 空(接口据此返回 degraded 空列表)。"""
r = get_meituan_city(0.0, -140.0) # 太平洋中部
assert r["city_id"] == "", f"境外不应给出 city_id: {r!r}"
def test_return_shape_and_types() -> None:
r = get_meituan_city(39.9042, 116.4074)
for key in ("city_id", "city_name", "province_name"):
assert key in r and isinstance(r[key], str)
def test_quantized_coords_hit_same_result() -> None:
"""相距 <1km(round 到 2 位小数后相同)的两点应解析出同一城市。"""
a = get_meituan_city(39.9042, 116.4074)
b = get_meituan_city(39.9031, 116.4066) # round 后同为 (39.90, 116.41)
assert a == b
def test_result_is_defensive_copy() -> None:
"""返回的是缓存副本:原地修改不应污染后续查询。"""
first = get_meituan_city(31.2304, 121.4737)
first["city_id"] = "TAMPERED"
second = get_meituan_city(31.2304, 121.4737)
assert second["city_id"] != "TAMPERED"