from unittest.mock import patch, MagicMock def test_parse_molit_rent_fields(): from app.listing_collector import _parse_molit_rent raw = {"aptNm": "OO아파트", "excluUseAr": "42.5", "deposit": "43,000", "monthlyRent": "0", "dealYear": "2026", "dealMonth": "5", "floor": "5"} d = _parse_molit_rent(raw, "아파트") assert d["complex_name"] == "OO아파트" and d["area"] == 42.5 assert d["deposit"] == 43000 and d["deal_type"] == "전세" and d["deal_ym"] == "202605" def test_parse_naver_article_fields(): from app.listing_collector import _parse_naver_article raw = {"articleNo": "A123", "tradeTypeName": "전세", "dealOrWarrantPrc": "2억 9,000", "areaName": "42", "area2": "42.5", "floorInfo": "5/15", "articleName": "OO아파트", "buildingName": "OO", "cortarNo": "1159010100"} d = _parse_naver_article(raw) assert d["article_no"] == "A123" and d["deal_type"] == "전세" and d["deposit"] == 29000 assert d["source"] == "naver" def test_collect_naver_block_sets_naver_ok_false(monkeypatch): """네이버 403 → 매물수집 skip + naver_ok=False, 실거래는 계속.""" from app import listing_collector as lc monkeypatch.setattr(lc, "_fetch_molit_all", lambda: (2, "calls=1 saved=2")) def boom(*a, **k): import requests raise requests.RequestException("403") monkeypatch.setattr(lc, "_fetch_naver_all", boom) r = lc.collect_listings() assert r["naver_ok"] is False # 안전마진(실거래)은 유지 def test_molit_call_returns_diag_on_http_error(monkeypatch): """MOLIT 401 등 HTTP 오류 → ([], diag) 반환, diag에 상태코드 포함(관측).""" from app import listing_collector as lc import requests monkeypatch.setattr(lc, "MOLIT_KEY", "TESTKEY") monkeypatch.setattr(lc.time, "sleep", lambda *a: None) # 재시도 대기 skip resp = MagicMock() resp.status_code = 401 resp.raise_for_status.side_effect = requests.HTTPError(response=resp) monkeypatch.setattr(lc.requests, "get", lambda *a, **k: resp) items, diag = lc._molit_call("getRTMSDataSvcAptTradeDev", "11590", "202606") assert items == [] assert diag and "401" in diag def test_collect_writes_molit_diag_to_log(monkeypatch): """collect_listings가 MOLIT/Naver 진단을 collect_log.error에 기록(silent-failure 관측).""" from app import listing_collector as lc from app import db monkeypatch.setattr(lc, "_fetch_molit_all", lambda: (0, "calls=36 saved=0 err=http=401")) monkeypatch.setattr(lc, "_fetch_naver_all", lambda: (0, 0)) lc.collect_listings() log = db.get_last_listing_collect_log() assert log is not None assert "http=401" in (log["error"] or "") assert "molit" in (log["error"] or "")