8.2 KiB
phase, plan, wave, title, depends_on, files_modified, autonomous, requirements
| phase | plan | wave | title | depends_on | files_modified | autonomous | requirements | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | 1 | 1 | 迁移前程无忧(job51)层至 crawler_core + mock 测试 |
|
true |
|
Phase 3 Plan 01: 迁移前程无忧(job51)层至 crawler_core + mock 测试
Objective
将 spiderJobs/platforms/job51/ 从依赖 spiderJobs.core(旧基类)改为依赖 crawler_core(新基类),
同时新增 tests/job51/test_job51_client.py mock 测试,满足 ARCH-04。
迁移与 Phase 2 Boss 完全对称:4 个文件修改 + sign.py 改桩 + 新增测试。
Must Haves
client.py继承crawler_core.http_client.HTTPClient,使用crawler_core.qcwy.sign.Job51Signapi.py使用crawler_core.base.Result/BaseFetcher/BaseSearcher,ApiResult全量替换为Resultapi.py中 2 处self._http替换为self.http_clientmain.pyimport 更新为crawler_core.basesign.py改为向后兼容桩(重新导出crawler_core.qcwy.sign.Job51Sign)python -c "from spiderJobs.platforms.job51.api import ...; from spiderJobs.platforms.job51.client import ..."无 ImportErrorgrep -rn "spiderJobs.core" spiderJobs/platforms/job51/{client,api,main,sign}.py无输出tests/job51/__init__.py存在tests/job51/test_job51_client.py存在pytest tests/job51/ -v全部通过(>= 15 个测试)
Wave 1
Task 1.1: 更新 client.py
<read_first>
spiderJobs/platforms/job51/client.py(当前内容)crawler_core/http_client.py(目标基类)crawler_core/qcwy/sign.py(Job51Sign 新来源) </read_first>
- 第 15 行改为:
from crawler_core.http_client import HTTPClient - 第 16 行改为:
(删除from crawler_core.qcwy.sign import Job51Signfrom spiderJobs.core.http_client import HTTPClient和from spiderJobs.platforms.job51.sign import Job51Sign)
其他所有内容(JOB51_HEADERS、Job51Client 类体、create_client 函数)不变。
<acceptance_criteria>
grep "from crawler_core.http_client import HTTPClient" spiderJobs/platforms/job51/client.py有输出grep "from crawler_core.qcwy.sign import Job51Sign" spiderJobs/platforms/job51/client.py有输出grep "spiderJobs.core" spiderJobs/platforms/job51/client.py无输出python -c "from spiderJobs.platforms.job51.client import Job51Client, create_client"无 ImportError </acceptance_criteria>
Task 1.2: 更新 api.py
<read_first>
spiderJobs/platforms/job51/api.py(当前完整内容,共 ~260 行)crawler_core/base.py(Result、BaseFetcher、BaseSearcher 接口) </read_first>
-
第 14 行改为:
from crawler_core.base import BaseFetcher, BaseSearcher, Result(删除
from spiderJobs.core.base import ApiResult, BaseFetcher, BaseSearcher) -
全文将
ApiResult替换为Result(共 11 处,包含函数注解和 return 语句) -
第 164 行:
http_code, data = self._http.get(endpoint)→http_code, data = self.http_client.get(endpoint) -
第 208 行:
http_code, data = self._http.get(self.ENDPOINT, self._build_params())→http_code, data = self.http_client.get(self.ENDPOINT, self._build_params())
_parse_job51_response 逻辑(status/1 判断、resultbody 解析)完全保留,只替换 ApiResult → Result。
<acceptance_criteria>
grep "from crawler_core.base import" spiderJobs/platforms/job51/api.py有输出grep "ApiResult" spiderJobs/platforms/job51/api.py无输出grep "self\._http" spiderJobs/platforms/job51/api.py无输出python -c "from spiderJobs.platforms.job51.api import SearchRecommendJobs, GetJobDetail, GetCompanyDetail, SearchCompanyJobs"无 ImportError </acceptance_criteria>
Task 1.3: 更新 main.py
<read_first>
spiderJobs/platforms/job51/main.py(当前内容) </read_first>
- 第 32 行改为:
(删除from crawler_core.base import BaseFetcher, BaseSearcherfrom spiderJobs.core.base import BaseFetcher, BaseSearcher)
其他内容不变。
<acceptance_criteria>
grep "from crawler_core.base import BaseFetcher, BaseSearcher" spiderJobs/platforms/job51/main.py有输出grep "spiderJobs.core" spiderJobs/platforms/job51/main.py无输出 </acceptance_criteria>
Task 1.4: 将 sign.py 改为向后兼容桩
<read_first>
spiderJobs/platforms/job51/sign.py(当前内容)crawler_core/qcwy/sign.py(权威实现) </read_first>
"""
向后兼容桩 — 前程无忧 (51Job) 签名
已迁移至 crawler_core.qcwy.sign。
直接从 crawler_core 重新导出,避免下游代码出现 ImportError。
"""
from crawler_core.qcwy.sign import Job51Sign # noqa: F401
__all__ = ["Job51Sign"]
<acceptance_criteria>
grep "from crawler_core.qcwy.sign import Job51Sign" spiderJobs/platforms/job51/sign.py有输出python -c "from spiderJobs.platforms.job51.sign import Job51Sign; print(Job51Sign.generate_uuid())"成功打印 UUID </acceptance_criteria>
Task 1.5: 创建 tests/job51/init.py
创建 `tests/job51/__init__.py`,内容:`# tests/job51/`<acceptance_criteria>
test -f tests/job51/__init__.py && echo "OK"输出 OK </acceptance_criteria>
Task 1.6: 编写 tests/job51/test_job51_client.py
<read_first>
spiderJobs/platforms/job51/api.py(迁移后版本)spiderJobs/platforms/job51/client.py(迁移后版本)crawler_core/qcwy/sign.py(Job51Sign 接口)tests/boss/test_boss_client.py(参考风格) </read_first>
-
TestParseJob51Response(纯函数):
test_http_error_returns_failure:HTTP 500 → success=Falsetest_status_zero_returns_failure:status=0 → success=Falsetest_status_one_with_resultbody_job_list:status=1,resultbody.jobList.items → list 解析正确test_status_one_no_items:status=1,无 items → success=True,list=[]test_non_dict_raw_returns_failure:raw 不是 dict → failure
-
TestSearchRecommendJobs:
test_search_success:正常返回职位列表test_search_http_error:HTTP 403
-
TestGetJobDetail:
test_fetch_success:成功返回 datatest_fetch_exception_handled:http_client.get抛异常 → success=False
-
TestGetCompanyDetail:
test_fetch_success:成功返回 data
-
TestJob51ClientHeaders:
test_headers_contain_sign:POST 后_job51_headers(sign="abc")["sign"]== "abc"test_headers_uuid_format:uuid 字段长度 >= 20
所有测试使用 MagicMock() mock http_client.get/post,无需网络。
<acceptance_criteria>
test -f tests/job51/test_job51_client.py && echo "OK"输出 OKpipenv run python -m pytest tests/job51/ -v全部通过(>= 12 个测试用例) </acceptance_criteria>
Verification
# 1. 验证所有 job51 模块 import 正确
pipenv run python -c "
from spiderJobs.platforms.job51.client import Job51Client, create_client
from spiderJobs.platforms.job51.api import SearchRecommendJobs, GetJobDetail, GetCompanyDetail
from spiderJobs.platforms.job51.main import main, create_searcher
from crawler_core.base import BaseFetcher, BaseSearcher
from spiderJobs.platforms.job51.api import SearchRecommendJobs
assert issubclass(SearchRecommendJobs, BaseSearcher)
print('✅ 所有 job51 模块 import 成功,继承关系正确')
"
# 2. 确认无旧依赖残留
grep -rn "spiderJobs.core" spiderJobs/platforms/job51/client.py spiderJobs/platforms/job51/api.py spiderJobs/platforms/job51/main.py spiderJobs/platforms/job51/sign.py && echo "❌ 仍有旧依赖" || echo "✅ 无旧依赖"
# 3. 运行 mock 测试
pipenv run python -m pytest tests/job51/ -v