Files
2026-05-29 13:27:41 +08:00

96 lines
3.5 KiB
Python

"""多比比新增端点的冒烟测试。LLM 调用被 monkeypatch 成固定 JSON,避免真打智谱。"""
from __future__ import annotations
from unittest.mock import patch
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
ARENA_JSON = (
'{"title":"iPhone 15 Pro 256GB","typical_price":8299.0,'
'"quotes":[{"platform":"淘宝","price":8099.0,"note":""},'
'{"platform":"京东","price":8299.0,"note":"自营"},'
'{"platform":"拼多多","price":7888.0,"note":"百亿补贴"},'
'{"platform":"抖音","price":8190.0,"note":""}]}'
)
WORTH_JSON = (
'{"score":78,"verdict":"buy","headline":"现在入手划算",'
'"reasons":["低于市场常见价约 2%","距下次大促还有一段时间"],'
'"typical_price":8299.0,"best_time":"现在就合适"}'
)
def test_arena_quote_basic() -> None:
with patch("app.api.arena.chat", return_value=ARENA_JSON):
r = client.post("/api/v1/arena-quote", json={"title": "iPhone 15 Pro 256GB"})
assert r.status_code == 200, r.text
body = r.json()
assert body["typical_price"] > 0
assert len(body["quotes"]) == 4
assert body["lowest_platform"] == "拼多多" # 7888 最低
def test_arena_quote_synthesizes_missing_platforms() -> None:
"""LLM 只给 1 个平台,其余平台应被确定性合成,保证每行有值。"""
only_one = '{"title":"x","typical_price":100.0,"quotes":[{"platform":"淘宝","price":95.0}]}'
with patch("app.api.arena.chat", return_value=only_one):
r = client.post(
"/api/v1/arena-quote",
json={"title": "x", "platforms": ["淘宝", "京东", "拼多多"]},
)
assert r.status_code == 200, r.text
quotes = r.json()["quotes"]
assert len(quotes) == 3
assert {q["platform"] for q in quotes} == {"淘宝", "京东", "拼多多"}
def test_arena_quote_empty_title() -> None:
r = client.post("/api/v1/arena-quote", json={"title": " "})
assert r.status_code == 422
def test_worth_buy_basic() -> None:
with patch("app.api.worth_buy.chat", return_value=WORTH_JSON):
r = client.post(
"/api/v1/worth-buy",
json={"title": "iPhone 15 Pro 256GB", "price": 8099.0},
)
assert r.status_code == 200, r.text
body = r.json()
assert 0 <= body["score"] <= 100
assert body["verdict"] in {"buy", "wait", "neutral"}
assert isinstance(body["reasons"], list) and body["reasons"]
def test_worth_buy_fallback_on_garbage() -> None:
"""LLM 返回非 JSON 垃圾时,接口仍给中性结论而非 5xx。"""
with patch("app.api.worth_buy.chat", return_value="不是 JSON 的废话"):
r = client.post("/api/v1/worth-buy", json={"title": "x", "price": 50.0})
assert r.status_code == 200, r.text
body = r.json()
assert body["typical_price"] > 0
assert body["verdict"] in {"buy", "wait", "neutral"}
def test_worth_buy_invalid_price() -> None:
r = client.post("/api/v1/worth-buy", json={"title": "x", "price": 0})
assert r.status_code == 422
def test_parse_ocr_boots_and_works() -> None:
"""parse-ocr 端点存在(修复了缺失 import),mock 延迟被关掉后能正常返回。"""
async def _instant(_seconds):
return None
with patch("app.mock_extractor.asyncio.sleep", _instant):
r = client.post(
"/api/v1/parse-ocr",
json={"ocr_text": "iPhone 15 Pro Max 256GB ¥8099 京东自营", "clusters": []},
)
assert r.status_code == 200, r.text
assert r.json()["price"] > 0