gendesign/tradein-mvp/backend/tests/test_insufficient_data_flag.py
bot-backend 01cc7057cd feat(tradein): insufficient_data flag on AggregatedEstimate (#697)
When no comps/anchor are found the estimate returns median=0/range 0-0, and
the frontend can render a literal «0 ₽». Add a computed boolean
insufficient_data (= median_price_rub <= 0) so the UI shows an explicit
«недостаточно данных» state instead.

Implemented as a Pydantic @computed_field derived from median_price_rub —
correct automatically across all four AggregatedEstimate construction sites
(main estimate, _empty_estimate, and both GET-rehydration paths), no DB column,
no risk of per-site drift. Additive/serialized; existing fields untouched.

Refs #697
2026-05-30 17:38:52 +03:00

49 lines
1.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#697 — AggregatedEstimate.insufficient_data computed flag.
median=0 (нет комплов/якоря) → insufficient_data=True, чтобы фронт показал
«недостаточно данных», а не «0 ₽». Производное от median_price_rub.
"""
import os
from datetime import UTC, datetime
from uuid import uuid4
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost/test_db")
from app.schemas.trade_in import AggregatedEstimate
def _estimate(median: int) -> AggregatedEstimate:
return AggregatedEstimate(
estimate_id=uuid4(),
median_price_rub=median,
range_low_rub=0 if median == 0 else median - 100,
range_high_rub=0 if median == 0 else median + 100,
median_price_per_m2=0 if median == 0 else 150_000,
confidence="low" if median == 0 else "medium",
n_analogs=0 if median == 0 else 12,
period_months=12,
analogs=[],
actual_deals=[],
expires_at=datetime(2026, 6, 1, tzinfo=UTC),
)
def test_insufficient_when_median_zero() -> None:
assert _estimate(0).insufficient_data is True
def test_sufficient_when_median_positive() -> None:
assert _estimate(6_900_000).insufficient_data is False
def test_flag_serialized_in_model_dump() -> None:
dump = _estimate(0).model_dump()
assert dump["insufficient_data"] is True
dump2 = _estimate(5_000_000).model_dump()
assert dump2["insufficient_data"] is False
def test_negative_median_is_insufficient() -> None:
# защита от случайного отрицательного headline.
assert _estimate(-1).insufficient_data is True