#!/usr/bin/env python3 """ HealthLink-HIS 三甲医院复杂业务逻辑全流程测试 覆盖: 门诊全流程、住院全流程、手术全流程、药品全流程、多角色协作、权限隔离 使用真实API调用,验证业务逻辑正确性 """ import requests import json import time import sys from datetime import datetime, timedelta BASE_URL = "http://localhost:18082/healthlink-his" RESULTS = [] PASSED = 0 FAILED = 0 ERRORS = [] # ======================== 测试用户 ======================== USERS = { "admin": {"username": "admin", "password": "admin123", "role": "超级管理员"}, "doctor": {"username": "doctor1", "password": "123456", "role": "医生"}, "jzys": {"username": "jzys", "password": "123456", "role": "急诊医生"}, "jzhs": {"username": "jzhs", "password": "123456", "role": "急诊护士"}, "nkhs": {"username": "nkhs1", "password": "123456", "role": "内科护士"}, "ssshs": {"username": "ssshs1", "password": "123456", "role": "手术室护士"}, "pharmacist": {"username": "yjk1", "password": "123456", "role": "药师"}, "tech": {"username": "医技员", "password": "123456", "role": "医技"}, "finance": {"username": "sfy", "password": "123456", "role": "收费员"}, "consultant": {"username": "hzzj1", "password": "123456", "role": "会诊专家"}, } # 缓存每个用户的token TOKEN_CACHE = {} def login(username, password): """登录并缓存token""" if username in TOKEN_CACHE and TOKEN_CACHE[username]: return TOKEN_CACHE[username] try: resp = requests.post(f"{BASE_URL}/login", json={ "username": username, "password": password, "tenantId": "1" }, timeout=10) data = resp.json() if data.get("code") == 200 and data.get("token"): TOKEN_CACHE[username] = data["token"] return data["token"] except Exception as e: print(f" ⚠️ 登录失败 {username}: {e}") return None def api(method, path, token=None, data=None, params=None, expected_code=200, desc=""): """统一API调用""" headers = {"Content-Type": "application/json"} if token: headers["Authorization"] = f"Bearer {token}" url = f"{BASE_URL}{path}" try: if method == "GET": resp = requests.get(url, headers=headers, params=params, timeout=30) elif method == "POST": resp = requests.post(url, headers=headers, json=data, timeout=30) elif method == "PUT": resp = requests.put(url, headers=headers, json=data, timeout=30) elif method == "DELETE": resp = requests.delete(url, headers=headers, timeout=30) else: return None result = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {"code": resp.status_code, "msg": resp.text[:200]} actual_code = result.get("code", resp.status_code) success = actual_code == expected_code return {"success": success, "code": actual_code, "data": result.get("data"), "msg": result.get("msg", ""), "raw": result} except requests.exceptions.Timeout: return {"success": False, "code": 0, "msg": "请求超时", "data": None} except Exception as e: return {"success": False, "code": 0, "msg": str(e)[:200], "data": None} def record(test_id, name, passed, details="", data_flow=""): """记录测试结果""" global PASSED, FAILED status = "✅" if passed else "❌" if passed: PASSED += 1 else: FAILED += 1 RESULTS.append({"id": test_id, "name": name, "passed": passed, "details": details}) flow_str = f" 📊 数据流: {data_flow}" if data_flow else "" print(f" {status} [{test_id}] {name}" + (f" — {details}" if details else "")) if flow_str: print(flow_str) # ======================== 1. 登录认证测试 ======================== def test_auth(): print("\n" + "="*60) print("📋 模块一: 登录认证与Token管理") print("="*60) # TC-AUTH-001: 管理员正常登录 token = login("admin", "admin123") record("TC-AUTH-001", "管理员正常登录", token is not None, f"获取token: {'✓' if token else '✗'}", "admin → /login → token") # TC-AUTH-002: 错误密码登录 result = api("POST", "/login", data={"username": "admin", "password": "wrong", "tenantId": "1"}, expected_code=500) record("TC-AUTH-002", "错误密码拒绝登录", not result["success"], f"返回: code={result['code']}", "admin(错误密码) → /login → 500") # TC-AUTH-003: 获取用户信息 result = api("GET", "/getInfo", token=token) record("TC-AUTH-003", "获取当前用户信息", result["success"], f"用户: {result['data'].get('user', {}).get('nickName', 'N/A') if result['data'] else 'N/A'}", "token → /getInfo → 用户信息") # TC-AUTH-004: 多角色登录 all_tokens = {} for key, user in USERS.items(): t = login(user["username"], user["password"]) all_tokens[key] = t record(f"TC-AUTH-004-{key}", f"{user['role']}({user['username']})登录", t is not None, f"token: {'✓' if t else '✗'}") # TC-AUTH-005: 获取菜单路由 result = api("GET", "/getRouters", token=token) menu_count = len(result["data"]) if result["data"] else 0 record("TC-AUTH-005", "获取菜单路由树", result["success"] and menu_count > 0, f"一级菜单: {menu_count}个", "/getRouters → 菜单树") return all_tokens # ======================== 2. 系统管理测试 ======================== def test_system(tokens): print("\n" + "="*60) print("📋 模块二: 系统管理") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-SYS-001: 用户列表 result = api("GET", "/system/user/list", token=admin_token, params={"pageNum": 1, "pageSize": 10}) user_count = result["data"].get("total", 0) if result["data"] else 0 record("TC-SYS-001", "用户列表分页查询", result["success"] and user_count > 0, f"总用户数: {user_count}", "/system/user/list → 分页数据") # TC-SYS-002: 角色列表 result = api("GET", "/system/role/list", token=admin_token, params={"pageNum": 1, "pageSize": 10}) role_count = result["data"].get("total", 0) if result["data"] else 0 record("TC-SYS-002", "角色列表分页查询", result["success"] and role_count > 0, f"总角色数: {role_count}", "/system/role/list → 分页数据") # TC-SYS-003: 部门树 result = api("GET", "/system/dept/list", token=admin_token) dept_count = len(result["data"]) if result["data"] else 0 record("TC-SYS-003", "部门树查询", result["success"], f"部门数: {dept_count}", "/system/dept/list → 部门树") # TC-SYS-004: 数据字典查询 result = api("GET", "/system/dict/type/list", token=admin_token, params={"pageNum": 1, "pageSize": 10}) dict_count = result["data"].get("total", 0) if result["data"] else 0 record("TC-SYS-004", "数据字典类型查询", result["success"], f"字典类型数: {dict_count}", "/system/dict/type/list → 字典类型") # TC-SYS-005: 数据字典数据查询 result = api("GET", "/system/dict/data/list", token=admin_token, params={"dictType": "sys_user_sex", "pageNum": 1, "pageSize": 10}) record("TC-SYS-005", "数据字典数据查询", result["success"], f"性别字典数据: {len(result['data'].get('rows', [])) if result['data'] else 0}条", "/system/dict/data/list → 性别字典") # TC-SYS-006: 系统配置查询 result = api("GET", "/system/config/list", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SYS-006", "系统配置查询", result["success"], f"配置数: {result['data'].get('total', 0) if result['data'] else 0}", "/system/config/list → 配置项") # TC-SYS-007: 通知公告列表 result = api("GET", "/system/notice/list", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SYS-007", "通知公告列表", result["success"], f"公告数: {result['data'].get('total', 0) if result['data'] else 0}", "/system/notice/list → 公告列表") # ======================== 3. 门诊全流程测试 ======================== def test_outpatient(tokens): print("\n" + "="*60) print("📋 模块三: 门诊全流程 (挂号→就诊→开方→收费→取药)") print("="*60) finance_token = tokens.get("finance") doctor_token = tokens.get("doctor") pharmacist_token = tokens.get("pharmacist") if not all([finance_token, doctor_token, pharmacist_token]): print(" ⚠️ 跳过: 关键角色未登录") return # --- 3.1 收费挂号 --- # TC-OP-001: 查询挂号科室 result = api("GET", "/charge-manage/register/init", token=finance_token) record("TC-OP-001", "挂号初始化-科室列表", result["success"], "获取科室数据", "/charge-manage/register/init → 科室列表") # TC-OP-002: 查询挂号医生 result = api("GET", "/charge-manage/register/init", token=finance_token) record("TC-OP-002", "挂号初始化-医生列表", result["success"], "获取医生数据", "/charge-manage/register/init → 医生列表") # TC-OP-003: 查询患者列表 result = api("GET", "/doctor-station/main/patient-list", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-003", "医生站-患者列表", result["success"], f"患者数: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/main/patient-list → 患者列表") # --- 3.2 医生诊疗 --- # TC-OP-004: 医生站待诊列表 result = api("GET", "/doctor-station/main/pending-list", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-004", "医生站-待诊列表", result["success"], f"待诊: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/main/pending-list → 待诊列表") # TC-OP-005: 医嘱列表 result = api("GET", "/doctor-station/advice/list", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-005", "医生站-医嘱列表", result["success"], f"医嘱数: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/advice/list → 医嘱列表") # TC-OP-006: 诊断列表 result = api("GET", "/doctor-station/diagnosis/list", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-006", "医生站-诊断列表", result["success"], f"诊断数: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/diagnosis/list → 诊断列表") # --- 3.3 药品管理 --- # TC-OP-007: 待发药列表 result = api("GET", "/pharmacy-manage/pending-medication/pending-medication-page", token=pharmacist_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-007", "药房-待发药列表", result["success"], f"待发药: {result['data'].get('total', 0) if result['data'] else 0}", "/pharmacy-manage/pending-medication/pending-medication-page → 待发药") # TC-OP-008: 西药发药 result = api("GET", "/pharmacy-manage/western-medicine-dispense/init", token=pharmacist_token) record("TC-OP-008", "药房-西药发药初始化", result["success"], "获取西药发药数据", "/pharmacy-manage/western-medicine-dispense/init → 发药初始化") # TC-OP-009: 药品追溯 result = api("GET", "/drugtrace/code/page", token=pharmacist_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-009", "药品追溯码查询", result["success"], f"追溯码: {result['data'].get('total', 0) if result['data'] else 0}", "/drugtrace/code/page → 追溯码列表") # --- 3.4 收费结算 --- # TC-OP-010: 门诊收费列表 result = api("GET", "/charge-manage/charge/list", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-010", "门诊收费列表", result["success"], f"收费记录: {result['data'].get('total', 0) if result['data'] else 0}", "/charge-manage/charge/list → 收费列表") # TC-OP-011: 退费列表 result = api("GET", "/charge-manage/refund/list", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-011", "门诊退费列表", result["success"], f"退费记录: {result['data'].get('total', 0) if result['data'] else 0}", "/charge-manage/refund/list → 退费列表") # TC-OP-012: 门诊病历记录 result = api("GET", "/charge-manage/charge/clinic-record", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-OP-012", "门诊病历记录", result["success"], f"病历数: {result['data'].get('total', 0) if result['data'] else 0}", "/charge-manage/charge/clinic-record → 病历记录") # ======================== 4. 住院全流程测试 ======================== def test_inpatient(tokens): print("\n" + "="*60) print("📋 模块四: 住院全流程 (入院→医嘱→护理→手术→出院)") print("="*60) doctor_token = tokens.get("doctor") nurse_token = tokens.get("nkhs") if not all([doctor_token, nurse_token]): print(" ⚠️ 跳过: 关键角色未登录") return # TC-IN-001: 住院登记列表 result = api("GET", "/inhospital-charge/register/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-001", "住院登记列表", result["success"], f"住院登记: {result['data'].get('total', 0) if result['data'] else 0}", "/inhospital-charge/register/page → 住院登记列表") # TC-IN-002: 患者首页 result = api("GET", "/patient-home-manage/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-002", "住院患者首页列表", result["success"], f"在院患者: {result['data'].get('total', 0) if result['data'] else 0}", "/patient-home-manage/page → 在院患者列表") # TC-IN-003: 预交金管理 result = api("GET", "/deposit-manage/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-003", "预交金管理列表", result["success"], f"预交金记录: {result['data'].get('total', 0) if result['data'] else 0}", "/deposit-manage/page → 预交金列表") # TC-IN-004: 护理记录 result = api("GET", "/nursing-record/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-004", "护理记录列表", result["success"], f"护理记录: {result['data'].get('total', 0) if result['data'] else 0}", "/nursing-record/page → 护理记录") # TC-IN-005: 生命体征 result = api("GET", "/vital-signs/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-005", "生命体征记录", result["success"], f"体征记录: {result['data'].get('total', 0) if result['data'] else 0}", "/vital-signs/page → 生命体征") # TC-IN-006: 生命体征图表 result = api("GET", "/vital-signs-chart/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-006", "生命体征图表", result["success"], "图表数据", "/vital-signs-chart/page → 图表") # TC-IN-007: 医嘱执行 result = api("GET", "/inhospitalnursestation/nursebilling/execute/list", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-007", "医嘱执行列表", result["success"], f"执行医嘱: {result['data'].get('total', 0) if result['data'] else 0}", "/inhospitalnursestation/nursebilling/execute/list → 医嘱执行") # TC-IN-008: 护理交班 result = api("GET", "/api/v1/nursing/handoff/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-008", "护理交班记录", result["success"], f"交班记录: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/nursing/handoff/page → 交班记录") # TC-IN-009: 护理评估 result = api("GET", "/api/v1/nursing/assessment/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-009", "护理评估列表", result["success"], f"评估记录: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/nursing/assessment/page → 评估列表") # TC-IN-010: 护理计划 result = api("GET", "/care-plan/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-010", "护理计划列表", result["success"], f"护理计划: {result['data'].get('total', 0) if result['data'] else 0}", "/care-plan/page → 护理计划") # TC-IN-011: 出院管理 result = api("GET", "/discharge/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-IN-011", "出院管理列表", result["success"], f"出院记录: {result['data'].get('total', 0) if result['data'] else 0}", "/discharge/page → 出院列表") # ======================== 5. 手术全流程测试 ======================== def test_surgery(tokens): print("\n" + "="*60) print("📋 模块五: 手术全流程 (申请→讨论→排程→执行)") print("="*60) doctor_token = tokens.get("doctor") nurse_token = tokens.get("ssshs") if not all([doctor_token, nurse_token]): print(" ⚠️ 跳过: 关键角色未登录") return # TC-SUR-001: 手术申请列表 result = api("GET", "/clinical-manage/surgery/surgery-page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-001", "手术申请列表", result["success"], f"手术申请: {result['data'].get('total', 0) if result['data'] else 0}", "/clinical-manage/surgery/surgery-page → 手术申请") # TC-SUR-002: 术前讨论 result = api("GET", "/preop-discussion/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-002", "术前讨论列表", result["success"], f"讨论记录: {result['data'].get('total', 0) if result['data'] else 0}", "/preop-discussion/page → 术前讨论") # TC-SUR-003: 手术排程 result = api("GET", "/clinical-manage/surgery-schedule/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-003", "手术排程列表", result["success"], f"排程记录: {result['data'].get('total', 0) if result['data'] else 0}", "/clinical-manage/surgery-schedule/page → 手术排程") # TC-SUR-004: 手术安全核查 result = api("GET", "/surgery-safety-check/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-004", "手术安全核查", result["success"], f"核查记录: {result['data'].get('total', 0) if result['data'] else 0}", "/surgery-safety-check/page → 安全核查") # TC-SUR-005: 麻醉记录 result = api("GET", "/api/v1/anesthesia/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-005", "麻醉记录列表", result["success"], f"麻醉记录: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/anesthesia/page → 麻醉记录") # TC-SUR-006: 麻醉增强 result = api("GET", "/anesthesia-enhanced/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-006", "麻醉增强管理", result["success"], f"增强记录: {result['data'].get('total', 0) if result['data'] else 0}", "/anesthesia-enhanced/page → 麻醉增强") # TC-SUR-007: 手术室管理 result = api("GET", "/base-data-manage/operating-room/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-007", "手术室管理", result["success"], f"手术室: {result['data'].get('total', 0) if result['data'] else 0}", "/base-data-manage/operating-room/page → 手术室列表") # TC-SUR-008: 手术室排班 result = api("GET", "/schedule-pool/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-SUR-008", "手术室排班", result["success"], f"排班记录: {result['data'].get('total', 0) if result['data'] else 0}", "/schedule-pool/page → 手术室排班") # ======================== 6. 医技检查全流程 ======================== def test_inspection(tokens): print("\n" + "="*60) print("📋 模块六: 医技检查全流程 (申请→采样→检验→报告)") print("="*60) tech_token = tokens.get("tech") doctor_token = tokens.get("doctor") if not all([tech_token, doctor_token]): print(" ⚠️ 跳过: 关键角色未登录") return # TC-INS-001: 检验申请单 result = api("GET", "/reg-doctorstation/request-form/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-001", "检验申请单列表", result["success"], f"申请单: {result['data'].get('total', 0) if result['data'] else 0}", "/reg-doctorstation/request-form/page → 申请单列表") # TC-INS-002: 标本采集 result = api("GET", "/inspection/collection/page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-002", "标本采集列表", result["success"], f"采集记录: {result['data'].get('total', 0) if result['data'] else 0}", "/inspection/collection/page → 标本采集") # TC-INS-003: 检验仪器 result = api("GET", "/inspection/instrument/information-page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-003", "检验仪器列表", result["success"], f"仪器: {result['data'].get('total', 0) if result['data'] else 0}", "/inspection/instrument/information-page → 仪器列表") # TC-INS-004: 检验标本 result = api("GET", "/inspection/specimen/information-page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-004", "检验标本列表", result["success"], f"标本: {result['data'].get('total', 0) if result['data'] else 0}", "/inspection/specimen/information-page → 标本列表") # TC-INS-005: 检验观察 result = api("GET", "/inspection/observation/information-page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-005", "检验观察结果", result["success"], f"观察: {result['data'].get('total', 0) if result['data'] else 0}", "/inspection/observation/information-page → 观察结果") # TC-INS-006: 检验科配置 result = api("GET", "/inspection/lisConfig/init-page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-006", "检验科配置", result["success"], "配置信息", "/inspection/lisConfig/init-page → 检验配置") # TC-INS-007: 标本条码 result = api("GET", "/specimen-barcode/page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-007", "标本条码管理", result["success"], f"条码: {result['data'].get('total', 0) if result['data'] else 0}", "/specimen-barcode/page → 条码管理") # TC-INS-008: 影像管理 result = api("GET", "/radiology-enhanced/page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-008", "影像增强管理", result["success"], f"影像: {result['data'].get('total', 0) if result['data'] else 0}", "/radiology-enhanced/page → 影像管理") # TC-INS-009: 影像对比 result = api("GET", "/radiology-comparison/page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-009", "影像对比管理", result["success"], f"对比: {result['data'].get('total', 0) if result['data'] else 0}", "/radiology-comparison/page → 影像对比") # TC-INS-010: 3D重建 result = api("GET", "/reconstruction/page", token=tech_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INS-010", "3D重建管理", result["success"], f"重建: {result['data'].get('total', 0) if result['data'] else 0}", "/reconstruction/page → 3D重建") # ======================== 7. 院感管理测试 ======================== def test_infection(tokens): print("\n" + "="*60) print("📋 模块七: 院感管理") print("="*60) nurse_token = tokens.get("nkhs") tech_token = tokens.get("tech") if not nurse_token: print(" ⚠️ 跳过: 护士未登录") return # TC-INF-001: 院感监测 result = api("GET", "/infection-enhanced/surveillance/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-001", "院感监测列表", result["success"], f"监测: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/surveillance/page → 院感监测") # TC-INF-002: 院感预警 result = api("GET", "/infection-enhanced/warning/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-002", "院感预警列表", result["success"], f"预警: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/warning/page → 院感预警") # TC-INF-003: 耐药监测 result = api("GET", "/infection-enhanced/mdr/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-003", "耐药监测列表", result["success"], f"耐药: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/mdr/page → 耐药监测") # TC-INF-004: 职业暴露 result = api("GET", "/infection-enhanced/exposure/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-004", "职业暴露列表", result["success"], f"暴露: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/exposure/page → 职业暴露") # TC-INF-005: 手卫生 result = api("GET", "/infection-enhanced/hand-hygiene/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-005", "手卫生管理", result["success"], f"手卫生: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/hand-hygiene/page → 手卫生") # TC-INF-006: 环境监测 result = api("GET", "/infection-enhanced/env-monitor/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-006", "环境监测列表", result["success"], f"环境监测: {result['data'].get('total', 0) if result['data'] else 0}", "/infection-enhanced/env-monitor/page → 环境监测") # TC-INF-007: 传染病直报 result = api("GET", "/api/v1/epidemic/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-INF-007", "传染病直报列表", result["success"], f"直报: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/epidemic/page → 传染病直报") # ======================== 8. 质量管理测试 ======================== def test_quality(tokens): print("\n" + "="*60) print("📋 模块八: 质量管理") print("="*60) admin_token = tokens.get("admin") doctor_token = tokens.get("doctor") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-QA-001: 质量增强 result = api("GET", "/quality-enhanced/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-001", "质量增强管理", result["success"], f"质量记录: {result['data'].get('total', 0) if result['data'] else 0}", "/quality-enhanced/page → 质量管理") # TC-QA-002: 质量统计 result = api("GET", "/quality-enhanced/statistics", token=admin_token) record("TC-QA-002", "质量统计", result["success"], "统计数据", "/quality-enhanced/statistics → 质量统计") # TC-QA-003: 质量缺陷 result = api("GET", "/quality-enhanced/defect/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-003", "质量缺陷列表", result["success"], f"缺陷: {result['data'].get('total', 0) if result['data'] else 0}", "/quality-enhanced/defect/page → 缺陷列表") # TC-QA-004: 处方点评 result = api("GET", "/api/v1/review/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-004", "处方点评列表", result["success"], f"点评: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/review/page → 处方点评") # TC-QA-005: 合理用药 result = api("GET", "/api/v1/rational-drug/interaction-rule/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-005", "合理用药规则", result["success"], f"规则: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/rational-drug/interaction-rule/page → 用药规则") # TC-QA-006: 合理用药统计 result = api("GET", "/api/v1/rational-drug/statistics", token=admin_token) record("TC-QA-006", "合理用药统计", result["success"], "统计数据", "/api/v1/rational-drug/statistics → 用药统计") # TC-QA-007: 病历质量 result = api("GET", "/api/v1/emr-quality/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-007", "病历质量列表", result["success"], f"病历质量: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/emr-quality/page → 病历质量") # TC-QA-008: 危急值管理 result = api("GET", "/api/v1/critical-value/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-008", "危急值管理", result["success"], f"危急值: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/critical-value/page → 危急值管理") # TC-QA-009: 临床路径 result = api("GET", "/clinical-pathway/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-009", "临床路径管理", result["success"], f"临床路径: {result['data'].get('total', 0) if result['data'] else 0}", "/clinical-pathway/page → 临床路径") # TC-QA-010: 医嘱闭环 result = api("GET", "/api/v1/order-closed-loop/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-QA-010", "医嘱闭环管理", result["success"], f"闭环: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/order-closed-loop/page → 医嘱闭环") # ======================== 9. 中医管理测试 ======================== def test_tcm(tokens): print("\n" + "="*60) print("📋 模块九: 中医管理") print("="*60) doctor_token = tokens.get("doctor") if not doctor_token: print(" ⚠️ 跳过: 医生未登录") return # TC-TCM-001: 中医传统诊疗 result = api("GET", "/api/v1/tcm/traditional/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-TCM-001", "中医传统诊疗列表", result["success"], f"诊疗: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/tcm/traditional/page → 中医诊疗") # TC-TCM-002: 中医体质辨识 result = api("GET", "/api/v1/tcm/constitution/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-TCM-002", "中医体质辨识", result["success"], f"体质: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/tcm/constitution/page → 体质辨识") # TC-TCM-003: 壮医特色 result = api("GET", "/api/v1/tcm/zuang-medicine/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-TCM-003", "壮医特色诊疗", result["success"], f"壮医: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/tcm/zuang-medicine/page → 壮医诊疗") # TC-TCM-004: 中医处方 result = api("GET", "/doctor-station/chinese-medical/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-TCM-004", "中医处方列表", result["success"], f"处方: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/chinese-medical/page → 中医处方") # ======================== 10. 急诊管理测试 ======================== def test_emergency(tokens): print("\n" + "="*60) print("📋 模块十: 急诊管理") print("="*60) jzys_token = tokens.get("jzys") jzhs_token = tokens.get("jzhs") if not all([jzys_token, jzhs_token]): print(" ⚠️ 跳过: 急诊角色未登录") return # TC-EM-001: 急诊分诊 result = api("GET", "/emergency/triage/page", token=jzys_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EM-001", "急诊分诊列表", result["success"], f"分诊: {result['data'].get('total', 0) if result['data'] else 0}", "/emergency/triage/page → 急诊分诊") # TC-EM-002: 分诊叫号 result = api("GET", "/triage/queue/list", token=jzhs_token) record("TC-EM-002", "分诊叫号队列", result["success"], "叫号队列", "/triage/queue/list → 叫号队列") # TC-EM-003: 急诊医生站 result = api("GET", "/emergency/page", token=jzys_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EM-003", "急诊患者列表", result["success"], f"急诊患者: {result['data'].get('total', 0) if result['data'] else 0}", "/emergency/page → 急诊患者") # TC-EM-004: 急诊护士站 result = api("GET", "/emergency/nurse/page", token=jzhs_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EM-004", "急诊护理列表", result["success"], f"急诊护理: {result['data'].get('total', 0) if result['data'] else 0}", "/emergency/nurse/page → 急诊护理") # ======================== 11. 会诊管理测试 ======================== def test_consultation(tokens): print("\n" + "="*60) print("📋 模块十一: 会诊管理") print("="*60) doctor_token = tokens.get("doctor") consultant_token = tokens.get("consultant") if not all([doctor_token, consultant_token]): print(" ⚠️ 跳过: 关键角色未登录") return # TC-CS-001: 会诊申请 result = api("GET", "/consultation/application/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-CS-001", "会诊申请列表", result["success"], f"会诊申请: {result['data'].get('total', 0) if result['data'] else 0}", "/consultation/application/page → 会诊申请") # TC-CS-002: 会诊确认 result = api("GET", "/consultation/confirmation/page", token=consultant_token, params={"pageNum": 1, "pageSize": 10}) record("TC-CS-002", "会诊确认列表", result["success"], f"会诊确认: {result['data'].get('total', 0) if result['data'] else 0}", "/consultation/confirmation/page → 会诊确认") # TC-CS-003: 会诊反馈 result = api("GET", "/consultation/feedback/page", token=consultant_token, params={"pageNum": 1, "pageSize": 10}) record("TC-CS-003", "会诊反馈列表", result["success"], f"会诊反馈: {result['data'].get('total', 0) if result['data'] else 0}", "/consultation/feedback/page → 会诊反馈") # TC-CS-004: 会诊超时提醒 result = api("GET", "/consultation/timeout/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-CS-004", "会诊超时提醒", result["success"], f"超时: {result['data'].get('total', 0) if result['data'] else 0}", "/consultation/timeout/page → 会诊超时") # ======================== 12. 病案管理测试 ======================== def test_medical_record(tokens): print("\n" + "="*60) print("📋 模块十二: 病案管理") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-MR-001: 病案首页 result = api("GET", "/api/v1/mr-homepage/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-MR-001", "病案首页列表", result["success"], f"病案: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/mr-homepage/page → 病案首页") # TC-MR-002: DRG分析 result = api("GET", "/drg-analysis/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-MR-002", "DRG分析列表", result["success"], f"DRG: {result['data'].get('total', 0) if result['data'] else 0}", "/drg-analysis/page → DRG分析") # TC-MR-003: 病案归档 result = api("GET", "/emr-archive/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-MR-003", "病案归档列表", result["success"], f"归档: {result['data'].get('total', 0) if result['data'] else 0}", "/emr-archive/page → 病案归档") # TC-MR-004: 病案质控 result = api("GET", "/api/v1/emr-quality/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-MR-004", "病案质控列表", result["success"], f"质控: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/emr-quality/page → 病案质控") # ======================== 13. 经营分析测试 ======================== def test_analytics(tokens): print("\n" + "="*60) print("📋 模块十三: 经营分析") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-AN-001: 经营分析 result = api("GET", "/business-analytics/overview", token=admin_token) record("TC-AN-001", "经营分析概览", result["success"], "经营数据", "/business-analytics/overview → 经营概览") # TC-AN-002: 药品库存预警 result = api("GET", "/pharmacy-stock-alert/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-AN-002", "药品库存预警", result["success"], f"预警: {result['data'].get('total', 0) if result['data'] else 0}", "/pharmacy-stock-alert/page → 库存预警") # TC-AN-003: 药品效期管理 result = api("GET", "/drug-expiry/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-AN-003", "药品效期管理", result["success"], f"效期: {result['data'].get('total', 0) if result['data'] else 0}", "/drug-expiry/page → 效期管理") # TC-AN-004: DRG绩效 result = api("GET", "/drg-analysis/performance", token=admin_token) record("TC-AN-004", "DRG绩效分析", result["success"], "绩效数据", "/drg-analysis/performance → DRG绩效") # TC-AN-005: 科室收入统计 result = api("GET", "/report-manage/department-revenue-statistics", token=admin_token) record("TC-AN-005", "科室收入统计", result["success"], "收入数据", "/report-manage/department-revenue-statistics → 收入统计") # TC-AN-006: 门诊收入 result = api("GET", "/report-manage/charge/init", token=admin_token) record("TC-AN-006", "门诊收费报表", result["success"], "报表数据", "/report-manage/charge/init → 门诊收费报表") # TC-AN-007: 挂号统计 result = api("GET", "/report-manage/register/init", token=admin_token) record("TC-AN-007", "挂号统计报表", result["success"], "统计数据", "/report-manage/register/init → 挂号统计") # ======================== 14. 权限隔离测试 ======================== def test_permission_isolation(tokens): print("\n" + "="*60) print("📋 模块十四: 权限隔离验证") print("="*60) # 不同角色应该不能访问管理功能 test_cases = [ # (角色key, 应该无权访问的路径, 描述) ("doctor", "/system/user/list", "医生→用户管理(应拒)"), ("doctor", "/system/role/list", "医生→角色管理(应拒)"), ("nurse", "/system/config/list", "护士→系统配置(应拒)"), ("pharmacist", "/system/user/list", "药师→用户管理(应拒)"), ("finance", "/system/role/list", "收费员→角色管理(应拒)"), ] for i, (user_key, path, desc) in enumerate(test_cases): token = tokens.get(user_key) if not token: record(f"TC-PERM-{i+1:03d}", f"{desc}(未登录)", False, "跳过") continue result = api("GET", path, token=token, expected_code=200) # 如果返回200说明没有权限隔离(这是一个已知问题) if result["success"]: record(f"TC-PERM-{i+1:03d}", f"{desc}", False, f"⚠️ 返回200 - 权限未隔离", f"{user_key} → {path} → 200(应403)") else: record(f"TC-PERM-{i+1:03d}", f"{desc}", True, f"已隔离(code={result['code']})", f"{user_key} → {path} → {result['code']}") # ======================== 15. 跨模块数据一致性测试 ======================== def test_cross_module(tokens): print("\n" + "="*60) print("📋 模块十五: 跨模块数据一致性") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-XMOD-001: 门诊→住院数据联动 result = api("GET", "/cross-module/patient-transfer", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-001", "门诊→住院数据联动", result["success"], "数据联动", "/cross-module/patient-transfer → 门诊转住院") # TC-XMOD-002: 医嘱→药房联动 result = api("GET", "/cross-module/advice-drug-link", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-002", "医嘱→药房联动", result["success"], "医嘱药品联动", "/cross-module/advice-drug-link → 医嘱药品") # TC-XMOD-003: 检查→报告联动 result = api("GET", "/cross-module/exam-report-link", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-003", "检查→报告联动", result["success"], "检查报告联动", "/cross-module/exam-report-link → 检查报告") # TC-XMOD-004: 收费→医保联动 result = api("GET", "/cross-module/charge-yb-link", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-004", "收费→医保联动", result["success"], "收费医保联动", "/cross-module/charge-yb-link → 收费医保") # TC-XMOD-005: 护理→医嘱联动 result = api("GET", "/cross-module/nursing-advice-link", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-005", "护理→医嘱联动", result["success"], "护理医嘱联动", "/cross-module/nursing-advice-link → 护理医嘱") # TC-XMOD-006: 手术→麻醉联动 result = api("GET", "/cross-module/surgery-anesthesia-link", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-XMOD-006", "手术→麻醉联动", result["success"], "手术麻醉联动", "/cross-module/surgery-anesthesia-link → 手术麻醉") # ======================== 16. 银行卡/三part支付测试 ======================== def test_payment(tokens): print("\n" + "="*60) print("📋 模块十六: 支付与结算") print("="*60) finance_token = tokens.get("finance") if not finance_token: print(" ⚠️ 跳过: 收费员未登录") return # TC-PAY-001: 患者建卡 result = api("GET", "/charge/patientCardRenewal/init", token=finance_token) record("TC-PAY-001", "患者建卡初始化", result["success"], "建卡数据", "/charge/patientCardRenewal/init → 建卡初始化") # TC-PAY-002: 三part支付 result = api("GET", "/three-part/pay/page", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-PAY-002", "三方支付列表", result["success"], f"支付: {result['data'].get('total', 0) if result['data'] else 0}", "/three-part/pay/page → 三方支付") # TC-PAY-003: 预交金管理 result = api("GET", "/inhospital-charge/advance-payment/page", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-PAY-003", "住院预交金列表", result["success"], f"预交金: {result['data'].get('total', 0) if result['data'] else 0}", "/inhospital-charge/advance-payment/page → 预交金") # TC-PAY-004: 医保目录 result = api("GET", "/yb-management/catalog/page", token=finance_token, params={"pageNum": 1, "pageSize": 10}) record("TC-PAY-004", "医保目录管理", result["success"], f"医保目录: {result['data'].get('total', 0) if result['data'] else 0}", "/yb-management/catalog/page → 医保目录") # ======================== 17. 传染病直报测试 ======================== def test_epidemic(tokens): print("\n" + "="*60) print("📋 模块十七: 传染病直报") print("="*60) nurse_token = tokens.get("nkhs") if not nurse_token: print(" ⚠️ 跳过: 护士未登录") return # TC-EPI-001: 传染病报告列表 result = api("GET", "/api/v1/epidemic/page", token=nurse_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EPI-001", "传染病报告列表", result["success"], f"报告: {result['data'].get('total', 0) if result['data'] else 0}", "/api/v1/epidemic/page → 传染病报告") # TC-EPI-002: 传染病统计 result = api("GET", "/api/v1/epidemic/statistics", token=nurse_token) record("TC-EPI-002", "传染病统计", result["success"], "统计数据", "/api/v1/epidemic/statistics → 传染病统计") # ======================== 18. 电子病历测试 ======================== def test_emr(tokens): print("\n" + "="*60) print("📋 模块十八: 电子病历(EMR)") print("="*60) doctor_token = tokens.get("doctor") admin_token = tokens.get("admin") if not doctor_token: print(" ⚠️ 跳过: 医生未登录") return # TC-EMR-001: 病历列表 result = api("GET", "/doctor-station/emr/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EMR-001", "电子病历列表", result["success"], f"病历: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/emr/page → 病历列表") # TC-EMR-002: 病历模板 result = api("GET", "/doctor-station/emr/template-page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EMR-002", "病历模板列表", result["success"], f"模板: {result['data'].get('total', 0) if result['data'] else 0}", "/doctor-station/emr/template-page → 病历模板") # TC-EMR-003: CDA文档 if admin_token: result = api("GET", "/fhir-cda/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EMR-003", "CDA文档列表", result["success"], f"CDA: {result['data'].get('total', 0) if result['data'] else 0}", "/fhir-cda/page → CDA文档") # TC-EMR-004: 知情同意 result = api("GET", "/informed-consent/page", token=doctor_token, params={"pageNum": 1, "pageSize": 10}) record("TC-EMR-004", "知情同意列表", result["success"], f"同意书: {result['data'].get('total', 0) if result['data'] else 0}", "/informed-consent/page → 知情同意") # ======================== 19. 基础数据管理测试 ======================== def test_base_data(tokens): print("\n" + "="*60) print("📋 模块十九: 基础数据管理") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return # TC-BD-001: 组织管理 result = api("GET", "/base-data-manage/organization/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-BD-001", "组织管理", result["success"], f"组织: {result['data'].get('total', 0) if result['data'] else 0}", "/base-data-manage/organization/page → 组织列表") # TC-BD-002: 科室管理 result = api("GET", "/base-data-manage/location/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-BD-002", "科室管理", result["success"], f"科室: {result['data'].get('total', 0) if result['data'] else 0}", "/base-data-manage/location/page → 科室列表") # TC-BD-003: 人员管理 result = api("GET", "/base-data-manage/practitioner/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-BD-003", "人员管理", result["success"], f"人员: {result['data'].get('total', 0) if result['data'] else 0}", "/base-data-manage/practitioner/page → 人员列表") # TC-BD-004: ICD10编码 result = api("GET", "/icd10/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-BD-004", "ICD10编码管理", result["success"], f"ICD10: {result['data'].get('total', 0) if result['data'] else 0}", "/icd10/page → ICD10列表") # TC-BD-005: 数据字典管理 result = api("GET", "/dict-dictionary/definition/page", token=admin_token, params={"pageNum": 1, "pageSize": 10}) record("TC-BD-005", "数据字典管理", result["success"], f"字典: {result['data'].get('total', 0) if result['data'] else 0}", "/dict-dictionary/definition/page → 字典列表") # ======================== 20. 报表管理测试 ======================== def test_reports(tokens): print("\n" + "="*60) print("📋 模块二十: 报表管理") print("="*60) admin_token = tokens.get("admin") if not admin_token: print(" ⚠️ 跳过: 管理员未登录") return report_endpoints = [ ("/report-manage/report/statistics", "报表统计"), ("/report-manage/report/init", "报表首页"), ("/report-manage/report-statistics/page", "报表统计列表"), ] for i, (path, name) in enumerate(report_endpoints): result = api("GET", path, token=admin_token, params={"pageNum": 1, "pageSize": 10}) record(f"TC-RPT-{i+1:03d}", name, result["success"], f"数据: {'✓' if result['data'] else '✗'}", f"{path} → {name}") # ======================== 主函数 ======================== def main(): global PASSED, FAILED print("=" * 70) print("🏥 HealthLink-HIS 三甲医院复杂业务逻辑全流程测试") print(f"📅 测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print(f"🌐 测试环境: {BASE_URL}") print("=" * 70) # 1. 登录认证 tokens = test_auth() # 2. 系统管理 test_system(tokens) # 3. 门诊全流程 test_outpatient(tokens) # 4. 住院全流程 test_inpatient(tokens) # 5. 手术全流程 test_surgery(tokens) # 6. 医技检查 test_inspection(tokens) # 7. 院感管理 test_infection(tokens) # 8. 质量管理 test_quality(tokens) # 9. 中医管理 test_tcm(tokens) # 10. 急诊管理 test_emergency(tokens) # 11. 会诊管理 test_consultation(tokens) # 12. 病案管理 test_medical_record(tokens) # 13. 经营分析 test_analytics(tokens) # 14. 权限隔离 test_permission_isolation(tokens) # 15. 跨模块数据一致性 test_cross_module(tokens) # 16. 支付与结算 test_payment(tokens) # 17. 传染病直报 test_epidemic(tokens) # 18. 电子病历 test_emr(tokens) # 19. 基础数据管理 test_base_data(tokens) # 20. 报表管理 test_reports(tokens) # 汇总 total = PASSED + FAILED pass_rate = (PASSED / total * 100) if total > 0 else 0 print("\n" + "=" * 70) print("📊 测试结果汇总") print("=" * 70) print(f" 总用例数: {total}") print(f" 通过: ✅ {PASSED}") print(f" 失败: ❌ {FAILED}") print(f" 通过率: {pass_rate:.1f}%") print() if FAILED > 0: print("❌ 失败用例:") for r in RESULTS: if not r["passed"]: print(f" - [{r['id']}] {r['name']}: {r['details']}") # 输出JSON报告 report = { "test_time": datetime.now().isoformat(), "environment": BASE_URL, "total": total, "passed": PASSED, "failed": FAILED, "pass_rate": f"{pass_rate:.1f}%", "results": RESULTS, } report_path = "/root/.openclaw/workspace/his-repo/MD/test/reports/06_business_logic_complex_report.json" import os os.makedirs(os.path.dirname(report_path), exist_ok=True) with open(report_path, "w", encoding="utf-8") as f: json.dump(report, f, ensure_ascii=False, indent=2) print(f"\n📄 报告已保存: {report_path}") return 0 if FAILED == 0 else 1 if __name__ == "__main__": sys.exit(main())