☰
阶段 08:后端测试与接口文档
2026/10/14 7:36:17 网站建设 项目流程

阶段 08:后端测试与接口文档

合辑:FastAPI × Vue3 JoyFit 系统阶段开发计划 |端:后端 |阶段:8 / 12 |前置阶段:阶段 07:后端活动首页模块

大家好,我是小马不起床。

目录

  1. 一、阶段目标
  2. 二、本阶段开发顺序
  3. 三、本阶段测试策略说明
  4. 四、本阶段文件清单
  5. 五、步骤 1:创建 OpenAPI 路径测试
  6. 六、步骤 2:创建权限种子测试
  7. 七、步骤 3:创建 Schema 校验测试
  8. 八、步骤 4:创建统一响应结构测试
  9. 九、步骤 5:创建 OpenAPI 导出脚本
  10. 十、步骤 7:运行测试与导出文档
  11. 十一、本阶段验收清单
  12. 十二、常见问题
  13. 十三、进入下一阶段的条件
  14. 十四、问题记录与修复方案

一、阶段目标

本阶段目标是在后端主要业务模块已经完成的基础上,补充稳定的自动化测试、检查 OpenAPI 接口文档,并整理后端交付给前端前的接口验收清单。

完成本阶段后,后端应具备以下能力:

  1. 自动检查核心接口是否出现在 OpenAPI 文档中。
  2. 自动检查初始化角色和权限是否完整。
  3. 自动检查核心 Schema 字段校验是否生效。
  4. 自动检查统一响应结构是否稳定。
  5. 可以导出openapi.json供前端、Apifox 或 Postman 使用。
  6. 形成后端接口验收清单,供进入前端阶段前逐项确认。

二、本阶段开发顺序

1. 创建 OpenAPI 路径测试 2. 创建权限种子测试 3. 创建 Schema 校验测试 4. 创建统一响应结构测试 5. 创建 OpenAPI 导出脚本 6. 创建接口验收清单 7. 运行 pytest 和导出 OpenAPI 文档

三、本阶段测试策略说明

本阶段先补充不依赖真实数据库写入的自动化测试。

原因:

  1. 当前项目使用 MySQL,直接在自动化测试中写真实开发库,容易污染手动测试的数据。
  2. SQLite 内存库和 MySQL 在BigInteger自增、日期时间、外键行为上并不完全一致,直接替换数据库容易出现假通过或假失败。
  3. 当前阶段的重点是确认接口注册、文档生成、权限种子、字段校验和响应格式稳定。

因此本阶段自动化测试重点是:

  1. OpenAPI 路由完整性。
  2. 权限种子完整性。
  3. Schema 字段校验。
  4. 响应结构契约。

真实 CRUD 接口通过 Swagger 或 Apifox 按验收清单进行人工联调。后续引入更完整测试体系时,可单独配置 MySQL 测试库。

四、本阶段文件清单

序号相对路径类型说明
1backend/tests/test_openapi.py新增检查 OpenAPI 核心路径和认证配置
2backend/tests/test_seed_permissions.py新增检查角色与权限种子
3backend/tests/test_schema_validation.py新增检查核心 Schema 校验
4backend/tests/test_response_contract.py新增检查统一响应结构
5backend/scripts/export_openapi.py新增导出 OpenAPI JSON 文件
6backend/docs/api_checklist.md新增后端接口验收清单

五、步骤 1:创建 OpenAPI 路径测试

相对路径

backend/tests/test_openapi.py

完整代码

fromapp.mainimportappdeftest_openapi_contains_core_paths()->None:schema=app.openapi()paths=set(schema["paths"].keys())expected_paths={"/api/health","/api/auth/token","/api/auth/login","/api/auth/me","/api/auth/permissions","/api/auth/menus","/api/system/roles","/api/system/permissions","/api/users","/api/stores","/api/course-categories","/api/courses","/api/action-categories","/api/actions","/api/content/slogans","/api/content/events","/api/home",}missing_paths=expected_paths-pathsassertnotmissing_paths,f"missing openapi paths:{sorted(missing_paths)}"deftest_openapi_has_security_scheme()->None:schema=app.openapi()components=schema.get("components",{})security_schemes=components.get("securitySchemes",{})assertsecurity_schemesassertany(scheme.get("type")=="oauth2"forschemeinsecurity_schemes.values())

注意事项

  1. 该测试不连接数据库,仅检查 FastAPI 已注册的接口文档。
  2. 若新增业务模块后遗漏路由注册,该测试可较早发现问题。
  3. 若后续接口路径调整,需同步修改expected_paths。

六、步骤 2:创建权限种子测试

相对路径

backend/tests/test_seed_permissions.py

完整代码

fromapp.db.seedimportDEFAULT_PERMISSIONS,DEFAULT_ROLES REQUIRED_ROLES={"admin","store_admin","coach","member",}REQUIRED_PERMISSIONS={"user:list","user:create","user:update","user:delete","role:list","role:create","role:update","role:delete","permission:list","store:list","store:create","store:update","store:delete","course:list","course:create","course:update","course:delete","action:list","action:create","action:update","action:delete","event:list","event:create","event:update","event:delete","slogan:list","slogan:create","slogan:update","slogan:delete",}deftest_default_roles_are_complete()->None:role_codes={role_codeforrole_code,role_nameinDEFAULT_ROLES}assertREQUIRED_ROLES.issubset(role_codes)deftest_default_permissions_are_complete()->None:permission_codes={permission_codeforpermission_code,permission_name,menu_pathinDEFAULT_PERMISSIONS}assertREQUIRED_PERMISSIONS.issubset(permission_codes)deftest_permission_codes_are_unique()->None:permission_codes=[permission_codeforpermission_code,permission_name,menu_pathinDEFAULT_PERMISSIONS]assertlen(permission_codes)==len(set(permission_codes))deftest_menu_permissions_have_expected_paths()->None:permission_paths={permission_code:menu_pathforpermission_code,permission_name,menu_pathinDEFAULT_PERMISSIONS}assertpermission_paths["user:list"]=="/users"assertpermission_paths["role:list"]=="/system/roles"assertpermission_paths["permission:list"]=="/system/permissions"assertpermission_paths["store:list"]=="/stores"assertpermission_paths["course:list"]=="/courses"assertpermission_paths["action:list"]=="/actions"assertpermission_paths["event:list"]=="/content/events"assertpermission_paths["slogan:list"]=="/content/slogans"

注意事项

  1. 该测试可防止后续修改seed.py时遗漏权限。
  2. 新增模块后,需将模块权限加入REQUIRED_PERMISSIONS。
  3. 菜单路径仅检查具有前端菜单含义的权限。

七、步骤 3:创建 Schema 校验测试

相对路径

backend/tests/test_schema_validation.py

完整代码

importpytestfrompydanticimportValidationErrorfromapp.schemas.actionimportActionCreatefromapp.schemas.contentimportActivityEventCreate,SloganCreatefromapp.schemas.userimportUserCreatedeftest_action_create_rejects_invalid_difficulty()->None:withpytest.raises(ValidationError):ActionCreate(action_name="杠铃卧推",category_id=1,action_difficulty=6,applicable_store_type=1,)deftest_action_create_rejects_invalid_store_type()->None:withpytest.raises(ValidationError):ActionCreate(action_name="杠铃卧推",category_id=1,action_difficulty=3,applicable_store_type=3,)deftest_slogan_create_rejects_invalid_status()->None:withpytest.raises(ValidationError):SloganCreate(slogan_name="首页主标语",slogan_content="用每一次训练,靠近更强的自己",status=2,)deftest_activity_event_create_accepts_date_string()->None:event=ActivityEventCreate(title="JoyFit 夏季力量挑战赛",event_date="2026-07-18",location="上海 JoyFit 徐汇店",status="报名中",description="面向会员开放的力量挑战赛。",)assertevent.event_date.isoformat()=="2026-07-18"deftest_user_create_rejects_bcrypt_unsafe_password_length()->None:withpytest.raises(ValidationError):UserCreate(role_id=1,username="too_long_password_user",password="x"*73,)

注意事项

  1. bcrypt对密码存在 72 字节限制,因此用户密码 Schema 限制最大长度为 72。
  2. 动作难度限定为 1 到 5。
  3. 动作适用门店类型限定为 1 到 2。
  4. Slogan 状态限定为 0 或 1。

八、步骤 4:创建统一响应结构测试

相对路径

backend/tests/test_response_contract.py

完整代码

fromdatetimeimportdate,datetimefromapp.utils.responseimportfail,successdeftest_success_response_contract()->None:body=success(data={"name":"JoyFit"})assertbody["code"]==200assertbody["message"]=="success"assertbody["data"]=={"name":"JoyFit"}deftest_fail_response_contract()->None:body=fail(message="permission denied",code=403)assertbody["code"]==403assertbody["message"]=="permission denied"assertbody["data"]isNonedeftest_response_json_encodes_date_and_datetime()->None:body=success(data={"event_date":date(2026,7,18),"created_at":datetime(2026,7,18,9,30,0),})assertbody["data"]["event_date"]=="2026-07-18"assertbody["data"]["created_at"]=="2026-07-18T09:30:00"

注意事项

  1. 所有接口响应应统一为code、message、data。
  2. 日期和时间由jsonable_encoder转换为字符串,便于前端消费。
  3. 若后续修改统一响应结构,需同步调整本测试。

九、步骤 5:创建 OpenAPI 导出脚本

相对路径

backend/scripts/export_openapi.py

完整代码

importjsonfrompathlibimportPathfromapp.mainimportapp OUTPUT_PATH=Path("docs/openapi.json")defmain()->None:schema=app.openapi()OUTPUT_PATH.parent.mkdir(parents=True,exist_ok=True)OUTPUT_PATH.write_text(json.dumps(schema,ensure_ascii=False,indent=2),encoding="utf-8",)print(f"OpenAPI schema exported to{OUTPUT_PATH}")if__name__=="__main__":main()

运行命令

确保当前目录是:

FastAPI_Vue3_JoyFit/backend

执行:

python scripts/export_openapi.py

运行后生成:

backend/docs/openapi.json

注意事项

  1. 运行脚本前无需启动 Uvicorn。
  2. 该脚本仅读取 FastAPI 路由和 Schema,不会写入业务数据库。
  3. 前端可将openapi.json导入 Apifox 或 Postman 查看接口。

十、步骤 7:运行测试与导出文档

(开发顺序中的步骤 6「创建接口验收清单」与阶段验收内容已合并至「十一、本阶段验收清单」,验收清单文件同步沉淀为backend/docs/api_checklist.md。)

运行测试

确保当前目录是:

FastAPI_Vue3_JoyFit/backend

执行:

pytest

预期结果:

所有测试通过

导出 OpenAPI

执行:

python scripts/export_openapi.py

预期生成:

backend/docs/openapi.json

查看 Swagger

启动服务:

uvicorn app.main:app--reload--host0.0.0.0--port8000

访问:

http://127.0.0.1:8000/docs

十一、本阶段验收清单

本节由原有的「接口验收清单」与「本阶段验收清单」两处章节合并而成,条目取两者并集并已去重。清单内容同步保存为backend/docs/api_checklist.md(文件清单第 6 项),供前端联调阶段逐项确认。

自动化测试与交付物

  • OpenAPI 路径测试通过,核心路径全部存在于 OpenAPI 文档
  • 权限种子测试通过,初始化角色和权限完整
  • Schema 校验测试通过,非法字段能被拒绝
  • 统一响应结构测试通过,code/message/data稳定
  • 成功导出docs/openapi.json
  • 接口验收清单文件docs/api_checklist.md已创建
  • pytest全部测试通过
  • Swagger 可以访问:http://127.0.0.1:8000/docs

启动检查

  • 已进入backend目录
  • 已激活.venv
  • .env数据库配置正确
  • MySQL 服务正常运行
  • 后端启动成功

登录认证

  • /api/auth/token可以获取 Swagger 授权 Token
  • /api/auth/login可以返回统一响应结构
  • /api/auth/me可以返回当前用户
  • /api/auth/permissions可以返回当前用户权限
  • /api/auth/menus可以返回当前用户菜单

系统权限

  • /api/system/roles可以查询角色
  • /api/system/permissions可以查询权限
  • 管理员账号拥有业务管理权限
  • 无权限账号访问管理接口返回 403

用户与门店

  • 用户列表可以分页查询
  • 用户可以新增
  • 用户可以修改
  • 用户状态可以修改
  • 用户档案可以维护
  • 省份列表可以查询
  • 门店可以新增、修改、删除
  • 用户可以绑定门店

课程模块

  • 课程分类可以新增、修改、删除
  • 课程可以新增、修改、删除
  • 课程列表支持分页查询
  • 登录用户可以收藏课程
  • 登录用户可以取消收藏课程
  • 登录用户可以查看课程收藏

动作库模块

  • 动作分类可以新增、修改、删除
  • 动作可以新增、修改、删除
  • 动作列表支持分页查询
  • 登录用户可以收藏动作
  • 登录用户可以取消收藏动作
  • 登录用户可以查看动作收藏

活动首页模块

  • Slogan 可以新增、修改、删除
  • Slogan 可以按状态查询
  • 活动可以新增、修改、删除
  • 活动列表支持分页查询
  • 活动列表支持状态和日期筛选
  • /api/home不登录也可以访问
  • /api/home返回启用状态的 Slogan
  • /api/home返回活动列表摘要

统一响应与错误

  • 成功响应包含code
  • 成功响应包含message
  • 成功响应包含data
  • 参数错误返回 422
  • 未登录返回 401
  • 无权限返回 403
  • 业务错误返回统一 JSON 结构

后端交付前检查

  • Swagger 中接口分组清晰
  • 所有接口路径与前端约定一致
  • 管理接口均有权限控制
  • 用户端接口不误用后台权限

使用说明

  1. 人工验收条目不参与自动化测试,需通过 Swagger 或 Apifox 逐项确认。
  2. 每完成一次后端阶段,需重新勾选一遍。
  3. 进入前端阶段前,至少完成登录、权限、课程、动作、活动首页的验收。

十二、常见问题

1.test_openapi_contains_core_paths失败

原因:

通常为新增接口未注册到backend/app/api/router.py,或测试中的路径与实际接口路径不一致。

修复:

  1. 打开 Swagger 查看真实路径。
  2. 若路由遗漏注册,补充api_router.include_router(...)。
  3. 若接口路径已调整,同步修改expected_paths。

2.test_default_permissions_are_complete失败

原因:

backend/app/db/seed.py中缺少某个业务权限。

修复:

  1. 对照失败信息中的权限代码。
  2. 将缺失权限补充到DEFAULT_PERMISSIONS。
  3. 重启服务,使种子数据自动补齐到数据库。

3.test_schema_validation失败

原因:

Schema 字段范围被改动,或测试用例与当前业务规则不一致。

修复:

  1. 若业务规则未变,修复 Schema。
  2. 若业务规则已调整,修改测试期望。

4.python scripts/export_openapi.py提示找不到app

原因:

命令未在backend目录下执行。

修复:

先进入:

cdbackend

再执行:

python scripts/export_openapi.py

5. 导出的 OpenAPI 没有最新接口

原因:

路由未注册,或导出前代码未保存。

修复:

  1. 确认对应路由文件已被backend/app/api/router.py引入。
  2. 重新执行导出脚本。
  3. 打开docs/openapi.json搜索接口路径。

十三、进入下一阶段的条件

本阶段为后端开发线的终点。满足以下全部条件后,进入前端线,即阶段 09:前端基础工程构建:

  1. pytest全部通过。
  2. docs/openapi.json可以生成。
  3. docs/api_checklist.md已创建。
  4. Swagger 能正常访问。
  5. 后端核心接口已完成人工验收。
  6. 后端接口路径和响应结构已稳定。

十四、问题记录与修复方案

本阶段实践中遇到问题时,完整记录报错原文,便于检索与定位。记录后按以下流程处理:

  1. 判断错误属于测试用例、权限种子、Schema 校验、OpenAPI 导出还是接口验收问题。
  2. 将修复方案按下方模板追加至本节底部。

问题追加格式

### 问题 N:问题标题 #### 报错现象 按下方模板记录报错信息。 #### 原因分析 说明报错产生的原因。 #### 修复办法 给出具体修复步骤。 #### 需要修改的文件 - 相对路径:xxx - 修改说明:xxx - 完整代码或补丁:xxx

问题 1:执行python3 scripts/export_openapi.py提示找不到app

报错现象

在backend目录下执行:

python3 scripts/export_openapi.py

报错:

ModuleNotFoundError: No module named 'app'
原因分析

直接以下列方式运行脚本时:

python3 scripts/export_openapi.py

Python 会优先将脚本所在目录backend/scripts加入模块搜索路径,而不会稳定地将backend根目录加入其中。

因此脚本中的:

fromapp.mainimportapp

无法找到backend/app这个包。

修复办法

在脚本开头将backend根目录加入sys.path。

需要修改的文件
  • 相对路径:backend/scripts/export_openapi.py
  • 修改说明:导入app.main前,先将项目后端根目录加入 Python 模块搜索路径
  • 完整代码:
importjsonimportsysfrompathlibimportPath BACKEND_DIR=Path(__file__).resolve().parents[1]ifstr(BACKEND_DIR)notinsys.path:sys.path.insert(0,str(BACKEND_DIR))fromapp.mainimportapp OUTPUT_PATH=BACKEND_DIR/"docs"/"openapi.json"defmain()->None:schema=app.openapi()OUTPUT_PATH.parent.mkdir(parents=True,exist_ok=True)OUTPUT_PATH.write_text(json.dumps(schema,ensure_ascii=False,indent=2),encoding="utf-8",)print(f"OpenAPI schema exported to{OUTPUT_PATH}")if__name__=="__main__":main()
修复后验证

确保当前目录是:

FastAPI_Vue3_JoyFit/backend

再次执行:

python3 scripts/export_openapi.py

预期结果:

OpenAPI schema exported to /Users/.../FastAPI_Vue3_JoyFit/backend/docs/openapi.json

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询