Plan 01 - QUAL-02: 三平台解析函数单元测试: - tests/ingest/test_configs_boss.py: 10 个测试 (_extract_job_id, _extract_company_name, _build_boss_push) - tests/ingest/test_configs_qcwy.py: 12 个测试 (_extract_job_id, _extract_update_dt, _extract_company_name, _build_qcwy_push) - tests/ingest/test_configs_zhilian.py: 12 个测试 (_extract_number, _extract_fpt, _extract_company_name, _build_zhilian_push) Plan 02 - QUAL-06: 爬虫入库统计 API + 前端监控区域: - job.py: GET /job/data/stats 端点(总量/今日/最近入库时间/近7天趋势) - web/src/api/index.js: getIngestStats() 方法 - monitoring.vue: 新增爬虫职位入库统计区域(三平台卡片 + 趋势表格) - job.py: Optional 导入修复 QUAL-07: 确认 monitor.vue 已有完整清洗队列功能,无需改动 Full regression: 146 passed (112 existing + 34 new)
110 lines
3.5 KiB
Python
110 lines
3.5 KiB
Python
"""
|
||
Boss直聘 ingest config 解析函数单元测试 — QUAL-02
|
||
覆盖 _extract_job_id / _extract_company_name / _build_boss_push
|
||
"""
|
||
|
||
from app.services.ingest.configs.boss import (
|
||
_extract_job_id,
|
||
_extract_company_name,
|
||
_build_boss_push,
|
||
)
|
||
|
||
|
||
# ─── _extract_job_id ─────────────────────────────────
|
||
|
||
def test_extract_job_id_from_jobBaseInfoVO():
|
||
data = {"jobBaseInfoVO": {"jobId": "ABCD123"}}
|
||
assert _extract_job_id(data) == "ABCD123"
|
||
|
||
|
||
def test_extract_job_id_converts_int():
|
||
data = {"jobBaseInfoVO": {"jobId": 999}}
|
||
assert _extract_job_id(data) == "999"
|
||
|
||
|
||
def test_extract_job_id_missing_inner():
|
||
"""jobBaseInfoVO 存在但无 jobId → None"""
|
||
data = {"jobBaseInfoVO": {}}
|
||
assert _extract_job_id(data) is None
|
||
|
||
|
||
def test_extract_job_id_missing_outer():
|
||
"""缺 jobBaseInfoVO → None"""
|
||
data = {}
|
||
assert _extract_job_id(data) is None
|
||
|
||
|
||
# ─── _extract_company_name ────────────────────────────
|
||
|
||
def test_extract_company_name_from_name():
|
||
data = {"name": "字节跳动"}
|
||
assert _extract_company_name(data) == "字节跳动"
|
||
|
||
|
||
def test_extract_company_name_from_companyFullInfoVO():
|
||
data = {"companyFullInfoVO": {"name": "腾讯科技"}}
|
||
assert _extract_company_name(data) == "腾讯科技"
|
||
|
||
|
||
def test_extract_company_name_missing():
|
||
data = {}
|
||
assert _extract_company_name(data) is None
|
||
|
||
|
||
# ─── _build_boss_push ─────────────────────────────────
|
||
|
||
def test_build_boss_push_full():
|
||
data = {
|
||
"bossBaseInfoVO": {"brandName": "字节"},
|
||
"jobBaseInfoVO": {
|
||
"positionName": "算法工程师",
|
||
"jobDesc": "负责推荐算法",
|
||
"degreeName": "本科",
|
||
"requiredSkills": ["Python", "TensorFlow"],
|
||
"salaryWelfareInfo": ["五险一金"],
|
||
"experienceName": "3-5年",
|
||
"lowSalary": 25,
|
||
"highSalary": 40,
|
||
"locationName": "北京",
|
||
"locationDesc": "朝阳区",
|
||
"encryptJobId": "ENC_JOB_001",
|
||
},
|
||
"brandComInfoVO": {
|
||
"brandName": "字节跳动",
|
||
"encryptBrandId": "ENC_BRAND_001",
|
||
"scaleName": "10000人以上",
|
||
"industryName": "互联网",
|
||
"introduce": "全球领先的科技公司",
|
||
},
|
||
}
|
||
result = _build_boss_push(data)
|
||
assert result is not None
|
||
assert result["source_type"] == "Boss直聘"
|
||
assert result["title"] == "算法工程师"
|
||
assert "ENC_JOB_001" in result["url"]
|
||
assert result["company_id"] == "ENC_BRAND_001"
|
||
assert result["company_name"] == "字节跳动"
|
||
assert "25" in result["salary"] and "40" in result["salary"]
|
||
|
||
|
||
def test_build_boss_push_partial():
|
||
"""缺字段不 raise,返回合理降级值"""
|
||
data = {}
|
||
result = _build_boss_push(data)
|
||
assert result is not None
|
||
assert result["source_type"] == "Boss直聘"
|
||
# safe_get 在缺字段时返回 None 或 '',两种均可接受
|
||
assert result["title"] in (None, "")
|
||
|
||
|
||
def test_build_boss_push_skill_join():
|
||
"""多技能列表通过 safe_join 拼接"""
|
||
data = {
|
||
"jobBaseInfoVO": {"requiredSkills": ["Go", "Rust"]},
|
||
"bossBaseInfoVO": {},
|
||
"brandComInfoVO": {},
|
||
}
|
||
result = _build_boss_push(data)
|
||
assert "Go" in result["skill"]
|
||
assert "Rust" in result["skill"]
|