3. 测试环境搭建

FHIR接口测试的第一步不是写用例,而是把“被测对象、测试数据、调用工具、版本基线”四件事固定下来。环境不稳定,后续所有断言都会变成噪声。本章围绕一个可复现的测试环境展开:先选型并部署FHIR服务器,再准备符合资源约束的测试数据,然后配置客户端工具,最后用版本控制与隔离策略保证环境可回滚、可并行。

一、FHIR服务器选型与部署

选型要回答三个问题:支持哪些FHIR版本(R4/R4B/R5)、支持哪些交互(RESTful CRUD、搜索、事务Bundle、批量操作)、是否内置校验与术语服务。教学与一致性验证场景推荐两类组合:

  • HAPI FHIR JPA Server:Java生态,支持R4/R5,内置$validate、术语服务、搜索参数,适合验证资源结构、基数、绑定与搜索行为。可用Docker快速启动。
  • Microsoft FHIR Server / Firely Server:适合验证特定厂商实现差异,尤其是搜索参数与分页行为。

以HAPI为例,最小部署命令如下(示例参数,非实测结果):

docker run -d --name hapi-fhir \
  -p 8080:8080 \
  -e hapi.fhir.fhir_version=R4 \
  -e hapi.fhir.allow_multiple_delete=true \
  hapiproject/hapi:latest

启动后访问 http://localhost:8080/fhir/metadata 获取CapabilityStatement,这是判断服务器能力的权威依据。重点核对:rest.resource中是否包含Patient、Observation、Encounter;interaction是否含search-type、create、update;searchParam是否含identifier、code、date。若metadata缺失某交互,测试用例应直接标记为“不支持”,而不是反复重试。

部署后先做一次“冒烟验证”:POST一个最小Patient,再GET回来,确认服务器可写可读,再进入正式测试数据准备。

二、测试数据准备

FHIR测试数据不是随便造几条JSON,而要覆盖三类边界:结构边界(必填元素缺失、基数越界)、术语边界(绑定值集内/外编码)、引用边界(引用存在/悬空/循环)。建议用Bundle批量导入,保证引用完整性。

示例:一个包含Patient与Observation的transaction Bundle,Observation.subject引用Patient。注意fullUrl与request.url的对应关系,这是事务提交能否成功的关键。

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "fullUrl": "urn:uuid:pat-001",
      "resource": {
        "resourceType": "Patient",
        "identifier": [{"system":"http://example.org/mrn","value":"MRN-001"}],
        "name": [{"family":"张","given":["三"]}],
        "gender": "male",
        "birthDate": "1980-05-12"
      },
      "request": {"method":"POST","url":"Patient"}
    },
    {
      "fullUrl": "urn:uuid:obs-001",
      "resource": {
        "resourceType": "Observation",
        "status": "final",
        "code": {"coding":[{"system":"http://loinc.org","code":"8867-4","display":"Heart rate"}]},
        "subject": {"reference":"urn:uuid:pat-001"},
        "valueQuantity": {"value":72,"unit":"beats/min","system":"http://unitsofmeasure.org","code":"/min"}
      },
      "request": {"method":"POST","url":"Observation"}
    }
  ]
}

数据准备要形成“数据集清单”:每条数据标注用途(正常/边界/异常)、预期结果(201/400/422)、依赖关系。这样测试执行时才能判断失败是服务器问题还是数据本身不合规。

三、客户端工具配置

常用工具分三类:交互式调试(Postman、Insomnia)、脚本化测试(curl、Python requests、HAPI客户端)、专业校验(FHIR Validator、Inferno)。配置要点是统一请求头与认证:

curl -X POST http://localhost:8080/fhir/Patient \
  -H "Content-Type: application/fhir+json" \
  -H "Accept: application/fhir+json" \
  -H "Authorization: Bearer test-token" \
  -d @patient.json

Postman中建议建立环境变量baseUrl、token,并在Tests脚本中写断言,例如检查返回resourceType与id是否存在。FHIR Validator用于离线校验资源是否符合StructureDefinition,命令示例:

java -jar validator_cli.jar patient.json \
  -version 4.0.1 \
  -ig hl7.fhir.r4.core#4.0.1

工具配置的核心是“同一份数据、同一组请求头、同一套断言”,避免因工具差异导致结果不可比。

四、版本控制与隔离环境设计

FHIR接口测试涉及三类版本:FHIR规范版本(R4/R4B/R5)、Implementation Guide版本、测试脚本与数据版本。三者必须一起纳入Git管理,目录建议如下:

fhir-test/
├── data/          # 测试数据Bundle
├── scripts/       # 测试脚本与断言
├── ig/            # 依赖的IG包
├── config/        # 环境变量与服务器配置
└── README.md      # 版本对应关系

隔离环境推荐“三环境”模型:dev用于调试,ci用于自动化回归,release用于发布前一致性验证。每个环境使用独立数据库与独立端口,通过环境变量切换,避免数据污染。CI环境中每次运行前执行docker compose down -v清空数据,再重新导入基线数据集,保证结果可复现。

不要在同一服务器上混用不同IG版本的测试数据,否则术语绑定与结构校验会互相干扰,导致“假失败”。
FHIR测试环境四层结构与隔离关系 ① FHIR服务器层 HAPI FHIR R4 :8080/fhir Firely Server 厂商差异验证 CapabilityStatement /metadata 能力核对 术语服务 $validate 结构/绑定校验 ② 测试数据层 正常数据集 Patient/Observation 边界数据集 缺失必填/基数越界 异常数据集 悬空引用/错误编码 Bundle事务 引用完整性 ③ 客户端工具层 Postman / Insomnia 交互式调试 curl / Python 脚本化回归 FHIR Validator 离线结构校验 统一请求头 Content-Type/Accept ④ 版本控制与隔离层 Git: data/scripts/ig dev 环境 ci 环境 release 环境 独立DB/端口 版本基线贯穿四层