Files
medical_training/test/swagger_cms_relation.py
T

145 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Swagger Try-it-out 等效脚本:CMS 医院管理员·师生关系管理(姓名+手机号版)。
覆盖本轮改动:CMS-REL-2 新增/编辑(必填 带教老师姓名+手机号 / 学生姓名+手机号)、
CMS-REL-4 导入/模板(4 列:带教医生姓名|手机号|学生姓名|手机号)、
CMS-REL-6/7 下拉数据源(doctors / students,姓名+手机号一并返回)。
运行方式:.venv\\Scripts\\python.exe test/swagger_cms_relation.py
前提:Django dev server 已在 http://127.0.0.1:8000 运行,Redis 已启动。
"""
import io
import sys
import json
import subprocess
import requests
from openpyxl import Workbook
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
BASE = 'http://127.0.0.1:8000'
PYTHON = r'D:\01Agent\medical_training\.venv\Scripts\python.exe'
CWD = r'D:\01Agent\medical_training'
REL = '/api/cms/teacher-student-relations/'
XLSX_CT = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
PASS, FAIL = 'PASS', 'FAIL'
results = []
PH = ['13700007001', '13700007002', '13700007003', '13700007004', '13700007009'] # D1 D2 S1 S2 admin
def log(api_id, method, url, expected, actual, detail=''):
exp = expected if isinstance(expected, (list, tuple)) else [expected]
st = PASS if actual in exp else FAIL
results.append((api_id, st))
print(f' {st} {api_id:<16} {method:<5} {url:<44} expect={str(expected):<10} got={actual} {detail}')
def django_eval(code):
pre = 'import django, os; os.environ.setdefault("DJANGO_SETTINGS_MODULE","config.settings"); django.setup()\n'
p = subprocess.run([PYTHON, '-c', pre + code], capture_output=True, text=True, cwd=CWD)
if p.returncode != 0:
print('[django_eval ERROR]', p.stderr[-1200:])
return p.stdout.strip()
def jb(r):
return r.json() if r.headers.get('content-type', '').startswith('application/json') else None
def make_xlsx(headers, rows):
wb = Workbook(); ws = wb.active
ws.append(headers)
for r in rows:
ws.append(r)
buf = io.BytesIO(); wb.save(buf); buf.seek(0)
return buf.read()
print('\n[准备] 建机构 + 医院管理员 + 2 医生 + 2 学生...')
setup = django_eval(
'from apps.user.models import User, Institution; from rest_framework_simplejwt.tokens import RefreshToken; '
'inst,_=Institution.objects.get_or_create(code="SWG_REL", defaults={"name":"师生关系联调院","type":"hospital"}); '
f'[User.all_objects.filter(phone__in={PH!r}).delete()]; '
f'd1=User.objects.create_user(username="{PH[0]}",password=None,phone="{PH[0]}",real_name="王医生",role_type="doctor",institution=inst,status=1); '
f'd2=User.objects.create_user(username="{PH[1]}",password=None,phone="{PH[1]}",real_name="李医生",role_type="doctor",institution=inst,status=1); '
f's1=User.objects.create_user(username="{PH[2]}",password=None,phone="{PH[2]}",real_name="赵同学",role_type="student",institution=inst,status=1); '
f's2=User.objects.create_user(username="{PH[3]}",password=None,phone="{PH[3]}",real_name="钱同学",role_type="student",institution=inst,status=1); '
f'hu=User.objects.create_user(username="{PH[4]}",password=None,phone="{PH[4]}",real_name="师生关系院管",role_type="hospital_admin",institution=inst,status=1); '
'print(str(RefreshToken.for_user(hu).access_token))'
)
HU = {'Authorization': f'Bearer {setup}'}
print('[准备] 完成\n')
print('=' * 100)
print(' CMS 师生关系管理(姓名+手机号)Swagger Try-it-out')
print('=' * 100)
# 权限
log('anon-401', 'GET', REL, 401, requests.get(f'{BASE}{REL}').status_code)
# CMS-REL-6/7 下拉数据源
r = requests.get(f'{BASE}{REL}doctors/', headers=HU); b = jb(r) or []
log('CMS-REL-6', 'GET', REL + 'doctors/', 200, r.status_code,
f'count={len(b)} sample={b[0] if b else None}')
r = requests.get(f'{BASE}{REL}students/', headers=HU); b = jb(r) or []
log('CMS-REL-7', 'GET', REL + 'students/', 200, r.status_code,
f'count={len(b)} sample={b[0] if b else None}')
# CMS-REL-2 新增(姓名+手机号)
payload = {'teacher_name': '王医生', 'teacher_phone': PH[0], 'student_name': '赵同学', 'student_phone': PH[2], 'relation_type': '指导'}
r = requests.post(f'{BASE}{REL}', json=payload, headers=HU); b = jb(r) or {}
rid = b.get('id')
log('CMS-REL-2-new', 'POST', REL, 201, r.status_code,
f'id={rid} t={b.get("teacher_name")}/{b.get("teacher_phone")} s={b.get("student_name")}/{b.get("student_phone")}')
# 缺姓名 → 400
r = requests.post(f'{BASE}{REL}', json={**payload, 'student_name': ''}, headers=HU)
log('REL-2-missing', 'POST', REL + '(缺学生姓名)', 400, r.status_code, f'code={(jb(r) or {}).get("code")}')
# 姓名与手机号不符 → 400
r = requests.post(f'{BASE}{REL}', json={**payload, 'teacher_name': '不存在'}, headers=HU)
log('REL-2-mismatch', 'POST', REL + '(姓名手机号不符)', 400, r.status_code, f'code={(jb(r) or {}).get("code")}')
# 重复 → 400
r = requests.post(f'{BASE}{REL}', json=payload, headers=HU)
log('REL-2-dup', 'POST', REL + '(重复)', 400, r.status_code, f'code={(jb(r) or {}).get("code")}')
# CMS-REL-2 编辑(改 status
if rid:
r = requests.post(f'{BASE}{REL}{rid}/update/', json={'status': 0}, headers=HU)
log('CMS-REL-2-edit', 'POST', f'{REL}{rid}/update/', 200, r.status_code, f'status={(jb(r) or {}).get("status")}')
# CMS-REL-4 模板
r = requests.get(f'{BASE}{REL}import-template/', headers=HU)
log('CMS-REL-4-tmpl', 'GET', REL + 'import-template/', 200, r.status_code, f'ct={r.headers.get("content-type","")[:40]}')
# CMS-REL-4 导入(4 列)
xlsx = make_xlsx(['带教医生姓名', '带教医生手机号', '学生姓名', '学生手机号'], [
['李医生', PH[1], '钱同学', PH[3]], # ✅
['不存在', '00000000000', '钱同学', PH[3]], # 医生不符 → 失败
])
r = requests.post(f'{BASE}{REL}import/', files={'file': ('rel.xlsx', xlsx, XLSX_CT)}, headers=HU)
b = jb(r) or {}
log('CMS-REL-4-import', 'POST', REL + 'import/', 200, r.status_code,
f'success={b.get("success")} failed={b.get("failed")}')
# CMS-REL-1 列表
r = requests.get(f'{BASE}{REL}', headers=HU)
log('CMS-REL-1-list', 'GET', REL, 200, r.status_code, f'count={(jb(r) or {}).get("count")}')
# 清理
django_eval(
'from apps.user.models import User; from apps.user.models import TeacherStudentRelation as T; '
f'T.all_objects.filter(teacher__phone__in={PH!r}).delete(); '
f'User.all_objects.filter(phone__in={PH!r}).delete(); print("cleaned")'
)
print('=' * 100)
total = len(results); passed = sum(1 for _, s in results if s == PASS); failed = total - passed
print(f' 总计: {total} | 通过: {passed} | 失败: {failed}')
if failed:
print(' 失败:', [a for a, s in results if s == FAIL]); sys.exit(1)
print(' ALL PASSED — 师生关系(姓名+手机号)接口验证通过!')
sys.exit(0)