4. 接口自动化测试框架选型与设计
医疗系统接口自动化测试的框架选型,不能只看工具是否流行,而要看它能否适配医疗业务的真实约束:接口协议多样(HTTP/HL7/FHIR/WebService)、数据敏感、环境隔离严格、回归频率高、审计要求强。Pytest + Requests + Allure + Jenkins 这一组合之所以在医疗项目中常见,是因为它分别覆盖了“用例组织与执行、协议请求与断言、结果可视化与追溯、持续集成与定时回归”四个关键能力,并且都能通过插件或配置与医疗场景对接。
四个组件在医疗项目中的职责边界
Requests 负责最底层的 HTTP 交互,适合封装统一的会话、超时、重试、证书校验和日志脱敏。医疗接口常涉及患者标识、就诊号、检验结果等敏感字段,因此请求层必须内置脱敏与审计日志,而不是把日志直接打印到控制台。Pytest 负责用例发现、参数化、夹具(fixture)和标记(marker),它把“一个接口用例”组织成可复用、可分组、可并行执行的测试单元。Allure 负责把执行结果转成可读报告,附加请求响应、步骤、附件和环境信息,便于测试、开发和业务方共同定位问题。Jenkins 负责触发、调度、环境参数注入和结果归档,把自动化从“本地能跑”推进到“每天定时跑、每次提交跑”。
需要强调的是,这四者不是简单叠加,而是分层协作。Requests 是执行层,Pytest 是调度与断言层,Allure 是观测层,Jenkins 是触发与治理层。分层清晰后,医疗项目中最常见的“环境切换混乱、用例互相污染、报告无法追溯”三类问题才有解。
医疗项目适配的关键设计点
第一,环境隔离。医疗系统通常有开发、测试、预生产、生产四套环境,接口地址、数据库、鉴权方式都不同。推荐用 Pytest 的 fixture 结合环境变量读取配置,例如通过 --env=uat 参数选择 config/uat.yaml,而不是在代码里硬编码 URL。第二,数据脱敏。Requests 的日志钩子应在写入前对 patientId、idCard、phone 等字段做掩码,Allure 附件同样要过滤,避免报告泄露真实患者信息。第三,鉴权与令牌。医疗接口常用 OAuth2 或院内统一认证,建议在 session 级 fixture 中获取 token 并自动刷新,避免每个用例重复登录。第四,协议适配。对于 HL7 v2 或 FHIR 接口,可在 Requests 之上再封装一层消息构造与解析,把 MLLP 或 JSON 的差异收敛到适配器里。
分层架构的落地方式
建议把项目目录划分为五层:config/ 放环境配置,core/ 放请求封装、断言工具、脱敏与日志,api/ 放各业务模块的接口定义,testcases/ 放 Pytest 用例,reports/ 放 Allure 结果。用例只调用 api/ 层的方法,不直接写 URL 和请求体;api/ 层只调用 core/ 层的请求方法,不关心断言;断言放在用例层,便于按业务场景组合。这样当接口地址或鉴权方式变化时,只需改 core/ 或 config/,用例基本不动。
下面给出一个可参考的请求封装示例,体现超时、重试与脱敏三个医疗项目必备能力:
import requests, time, logging
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
SENSITIVE = ["patientId", "idCard", "phone", "name"]
def mask(data):
if isinstance(data, dict):
return {k: ("***" if k in SENSITIVE else mask(v)) for k, v in data.items()}
if isinstance(data, list):
return [mask(i) for i in data]
return data
class ApiClient:
def __init__(self, base_url, token=None, timeout=10):
self.base_url = base_url.rstrip("/")
self.timeout = timeout
self.session = requests.Session()
retry = Retry(total=2, backoff_factor=0.5,
status_forcelist=[500, 502, 503, 504])
self.session.mount("https://", HTTPAdapter(max_retries=retry))
if token:
self.session.headers["Authorization"] = f"Bearer {token}"
def request(self, method, path, **kwargs):
url = f"{self.base_url}{path}"
kwargs.setdefault("timeout", self.timeout)
logging.info("REQ %s %s %s", method, url, mask(kwargs.get("json")))
resp = self.session.request(method, url, **kwargs)
logging.info("RESP %s %s", resp.status_code, mask(resp.text[:500]))
return resp
在 Pytest 中,可以用 fixture 把 ApiClient 注入到用例,并通过 marker 区分冒烟、回归、专项:
import pytest
from core.client import ApiClient
@pytest.fixture(scope="session")
def client(env_config):
return ApiClient(env_config["base_url"], token=env_config["token"])
@pytest.mark.smoke
def test_query_patient(client):
resp = client.request("GET", "/api/patient/1001")
assert resp.status_code == 200
assert resp.json()["code"] == "0"
执行时通过 pytest -m smoke --alluredir=reports/allure-results 生成结果,再由 allure generate 转成 HTML 报告。Jenkins 中配置参数化构建,把 ENV 作为环境变量传入,构建后归档 reports/ 并发布 Allure 报告。这样一条从代码提交到报告可追溯的链路就完整了。
选型对比与判断依据
| 维度 | Pytest + Requests + Allure + Jenkins | Robot Framework 方案 | 纯 Postman/Newman 方案 |
|---|---|---|---|
| 代码复用与分层 | 强,Python 生态灵活 | 中,关键字驱动 | 弱,脚本化为主 |
| 医疗协议扩展 | 强,可封装 HL7/FHIR | 中,需自定义库 | 弱 |
| 报告与审计 | Allure 步骤、附件、环境齐全 | 自带报告,定制有限 | 报告较简单 |
| CI 集成 | Jenkins 原生支持 | 支持 | Newman 可集成 |
| 团队门槛 | 需 Python 基础 | 较低 | 最低 |
如果团队已有 Python 能力、接口协议复杂、审计要求高,优先选择 Pytest 组合;如果测试人员以业务为主、代码能力弱,可考虑 Robot Framework;Postman/Newman 更适合接口调试和少量冒烟,不适合作为医疗核心回归框架。选型没有绝对优劣,关键是让框架能力与项目约束匹配。