test(mapping): 增加健康档案映射样本基线(T-205)
This commit is contained in:
+1
-1
@@ -32,7 +32,7 @@
|
||||
- [x] `osi/jkda.go`:Find/FindRqbj(T-203;Find 已真实请求验收,FindRqbj 已按文档契约单测覆盖)。
|
||||
- [ ] `osi/jkda.go`:Create/Update(T-206,依赖映射与字典缓存)。
|
||||
- [ ] `handler` + `router`:暴露 `/api/health-record/save`(server 模式联调用)。
|
||||
- [ ] 用 01 文档样例 + 联调样本写映射单测。
|
||||
- [x] 用 01 文档样例 + 联调样本写映射单测。
|
||||
- **验收**:一条 PHIS 档案 → 映射 → create → 平台返回成功码(实测 `"01"`)与 `phrId`;重复投递被幂等跳过。
|
||||
|
||||
## 阶段 3 · 投递流水线
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-07
|
||||
- 阶段:**Phase M 映射层主体已起步**;T-001~T-006、T-201、T-203、T-102、T-202 已验收,下一步进入 T-205
|
||||
- 阶段:**Phase M 映射层基线完成**;T-001~T-006、T-201、T-203、T-102、T-202、T-205 已验收,下一步进入 Phase D 的 T-101
|
||||
- 技术栈:Go 1.24 单二进制;`main.go -mode server|deliver`;配置读取使用 viper,支持环境变量覆盖;OSI 客户端已具备签名、信封、传输、基础判码、JKDA00002 Find 与 JKDA00005 FindRqbj
|
||||
- 生产代码:已有 `main.go`、`config/`、`contract/envelope.go`、`osi/sign.go`、`osi/transport.go`、`osi/codes.go`、`osi/client.go`、`verify_jkda.go`、`go.mod`/`go.sum`;`contract/jkda.go` 已建立 JKDA00002 查询响应契约;`osi/jkda.go` 已实现 Find/FindRqbj;`mapping/dict.go` 已建立码表基线;`mapping/health_record.go` 与 `mapping/checkid.go` 已建立映射纯函数基线;`pipeline/` 等业务模块仍待后续任务建立
|
||||
- 生产代码:已有 `main.go`、`config/`、`contract/envelope.go`、`osi/sign.go`、`osi/transport.go`、`osi/codes.go`、`osi/client.go`、`verify_jkda.go`、`go.mod`/`go.sum`;`contract/jkda.go` 已建立 JKDA00002 查询响应契约;`osi/jkda.go` 已实现 Find/FindRqbj;`mapping/dict.go` 已建立码表基线;`mapping/health_record.go` 与 `mapping/checkid.go` 已建立映射纯函数基线;映射样本回归基线已完成;`pipeline/` 等业务模块仍待后续任务建立
|
||||
- 联调现实:**JKDA00002 个人档案查询已用 Go 侧真实请求打通**,返回 `code="01" message="操作成功" data_count=1`;Python 联调样本和实测契约沉淀在 `docs/04 §8`
|
||||
- 测试:`go test ./...` 通过;当前测试覆盖 mode 解析、配置加载与环境变量覆盖、MD5 签名、请求头组装、JSON POST 传输、头名大小写保留、identity 响应编码声明、超时配置、SOCKS5 代理地址校验、信封结构、serviceId 路由、成功/重试判码、Client.Call 请求与响应解析、JKDA00002 查询响应契约、JKDA00002 Find、JKDA00005 FindRqbj、映射码表双向查找、民族 01~56 完整性、健康档案映射必填/码表校验、checkId 确定性、JKDA00002 验证入口
|
||||
- 测试:`go test ./...` 通过;当前测试覆盖 mode 解析、配置加载与环境变量覆盖、MD5 签名、请求头组装、JSON POST 传输、头名大小写保留、identity 响应编码声明、超时配置、SOCKS5 代理地址校验、信封结构、serviceId 路由、成功/重试判码、Client.Call 请求与响应解析、JKDA00002 查询响应契约、JKDA00002 Find、JKDA00005 FindRqbj、映射码表双向查找、民族 01~56 完整性、健康档案映射必填/码表校验、checkId 确定性、docx/联调风格映射样本基线、JKDA00002 验证入口
|
||||
- 标准启动路径:`./init.sh` 已配置三步:依赖下载、`go test ./...`、`go run . -mode server -config config.yaml.example`
|
||||
- 标准验证路径:`go test ./...`、`go build ./...`
|
||||
- 当前 blocker:无硬 blocker。软限制:当前机器从 Git Bash 启动 Go 会出现标准库路径/构建缓存权限异常,`init.sh` 无法完整跑完;PowerShell 下等价 Go 命令和真实请求通过。厂家侧 B1/B2/B4/B5 契约缺口只影响阶段 4,不阻塞 Phase Q/M/D 的当前路径
|
||||
@@ -37,6 +37,7 @@
|
||||
| `config.yaml` | 已有·不入库 | 真实凭据;不要提交 |
|
||||
| `mapping/dict.go` | 已有 | 性别/民族/血型/RH/文化程度/职业/婚姻/医保/personSign 双向码表;未命中返回 `ValidationError` |
|
||||
| `mapping/health_record.go` `mapping/checkid.go` | 已有 | 健康档案映射草稿、字典快照注入、必填/码表校验、确定性 checkId |
|
||||
| `mapping/health_record_baseline_test.go` | 已有 | docx 风格、联调风格、脏数据映射回归样本 |
|
||||
| `pipeline/` 等 | 待建 | 后续任务 |
|
||||
|
||||
## 已验证事实(写代码时直接依赖)
|
||||
@@ -72,8 +73,8 @@ python3 scripts/query_health_record.py
|
||||
|
||||
## 下一步
|
||||
|
||||
1. T-205:映射单测基线,补 docx 样例 + 联调样本风格的回归用例。
|
||||
2. T-101:映射基线完成后进入真实字典服务。
|
||||
1. T-101:`osi/public.go` 四个字典查询(网格/责任医生/药品/机构)。
|
||||
2. T-103:字典缓存(T-101 后)。
|
||||
|
||||
## 维护规则
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package mapping
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDocxStyleHealthRecordMappingBaseline(t *testing.T) {
|
||||
src := PHISHealthRecord{
|
||||
SourceSystem: "PHIS",
|
||||
SourceRecordID: "docx-sample-001",
|
||||
UpdatedAt: "20260707100000",
|
||||
IDCard: "440000********0001",
|
||||
PersonName: "文档样例",
|
||||
SexCode: "2",
|
||||
Birthday: "1988-08-08",
|
||||
MobileNumber: "13800000001",
|
||||
RegionCode: "441625000000",
|
||||
ManaDoctorID: "D100",
|
||||
ManaUnitID: "123456789",
|
||||
NationCode: "01",
|
||||
EducationCode: "20",
|
||||
WorkCode: "4",
|
||||
MaritalStatusCode: "10",
|
||||
BloodTypeCode: "3",
|
||||
RhBloodCode: "3",
|
||||
InsuranceCode: "02",
|
||||
}
|
||||
|
||||
got, errs := MapHealthRecord(src, MapContext{Dicts: DefaultDictSnapshot()})
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("errors = %#v", errs)
|
||||
}
|
||||
assertMappedBaseline(t, got, MappedHealthRecord{
|
||||
CheckID: GenerateCheckID("PHIS", "JKDA", "docx-sample-001", "20260707100000"),
|
||||
IDCard: "440000********0001",
|
||||
PersonName: "文档样例",
|
||||
SexCode: "2",
|
||||
Birthday: "1988-08-08",
|
||||
MobileNumber: "13800000001",
|
||||
RegionCode: "441625000000",
|
||||
ManaDoctorID: "D100",
|
||||
ManaUnitID: "123456789",
|
||||
NationCode: "01",
|
||||
EducationCode: "20",
|
||||
WorkCode: "4",
|
||||
MaritalStatusCode: "10",
|
||||
BloodTypeCode: "3",
|
||||
RhBloodCode: "3",
|
||||
InsuranceCode: "02",
|
||||
})
|
||||
}
|
||||
|
||||
func TestJointDebugStyleHealthRecordMappingBaseline(t *testing.T) {
|
||||
src := PHISHealthRecord{
|
||||
SourceSystem: "PHIS",
|
||||
SourceRecordID: "joint-debug-001",
|
||||
UpdatedAt: "20260707110000",
|
||||
IDCard: "440000********1234",
|
||||
PersonName: "联调样例",
|
||||
SexCode: "1",
|
||||
Birthday: "1970-01-01",
|
||||
MobileNumber: "13900000000",
|
||||
RegionCode: "441625000000",
|
||||
ManaDoctorID: "D001",
|
||||
ManaUnitID: "123456789",
|
||||
NationCode: "01",
|
||||
EducationCode: "31",
|
||||
WorkCode: "Y",
|
||||
MaritalStatusCode: "20",
|
||||
BloodTypeCode: "4",
|
||||
RhBloodCode: "1",
|
||||
InsuranceCode: "01",
|
||||
}
|
||||
|
||||
got, errs := MapHealthRecord(src, MapContext{Dicts: DefaultDictSnapshot()})
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("errors = %#v", errs)
|
||||
}
|
||||
if got.CheckID != GenerateCheckID("PHIS", "JKDA", "joint-debug-001", "20260707110000") {
|
||||
t.Fatalf("checkId = %q", got.CheckID)
|
||||
}
|
||||
if got.IDCard != "440000********1234" || got.PersonName != "联调样例" || got.NationCode != "01" || got.WorkCode != "Y" {
|
||||
t.Fatalf("mapped = %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthRecordMappingBaselineRejectsDirtySample(t *testing.T) {
|
||||
src := PHISHealthRecord{
|
||||
SourceSystem: "PHIS",
|
||||
SourceRecordID: "dirty-001",
|
||||
UpdatedAt: "20260707120000",
|
||||
IDCard: "",
|
||||
PersonName: "脏数据样例",
|
||||
SexCode: "9",
|
||||
Birthday: "1970-01-01",
|
||||
MobileNumber: "",
|
||||
RegionCode: "441625000000",
|
||||
ManaDoctorID: "D001",
|
||||
ManaUnitID: "123456789",
|
||||
NationCode: "98",
|
||||
EducationCode: "31",
|
||||
WorkCode: "Y",
|
||||
MaritalStatusCode: "20",
|
||||
BloodTypeCode: "4",
|
||||
RhBloodCode: "1",
|
||||
InsuranceCode: "88",
|
||||
}
|
||||
|
||||
_, errs := MapHealthRecord(src, MapContext{Dicts: DefaultDictSnapshot()})
|
||||
assertValidationField(t, errs, "idCard", "required")
|
||||
assertValidationField(t, errs, "mobileNumber", "required")
|
||||
assertValidationCode(t, errs, "nationCode", "98")
|
||||
assertValidationCode(t, errs, "insuranceCode", "88")
|
||||
}
|
||||
|
||||
func assertMappedBaseline(t *testing.T, got MappedHealthRecord, want MappedHealthRecord) {
|
||||
t.Helper()
|
||||
if got != want {
|
||||
t.Fatalf("mapped = %#v\nwant = %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func assertValidationCode(t *testing.T, errs []ValidationError, field string, code string) {
|
||||
t.Helper()
|
||||
for _, err := range errs {
|
||||
if err.Field == field && err.Code == code {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("missing validation error field=%s code=%s in %#v", field, code, errs)
|
||||
}
|
||||
@@ -140,3 +140,10 @@
|
||||
- 验证:按 TDD 先运行 `go test ./mapping -run "TestMapHealthRecord|TestGenerateCheckID" -count=1`,因 `MapHealthRecord`/`MapContext`/`GenerateCheckID` 未定义失败;实现后目标测试通过。最终 `go test ./mapping -count=1`、`go test ./...`、`go build ./...`、`git diff --check` 均通过。
|
||||
- 决策:创建请求结构体仍留到 T-206;T-202 只输出映射层草稿结构,先把纯函数、校验、字典注入和 checkId 稳定性打牢。
|
||||
- 下一步:T-205(映射单测基线:docx 样例 + 联调样本)。
|
||||
## 2026-07-07 T-205 映射单测基线
|
||||
|
||||
- 状态:DONE
|
||||
- 变更:新增 `mapping/health_record_baseline_test.go`;补 docx 风格完整样例、联调样本风格脱敏样例、脏数据样例三组映射回归测试,覆盖主数据字段映射、码表转换、必填校验、码表未命中和 checkId 稳定生成。
|
||||
- 验证:`go test ./mapping -count=1` 通过;`go test ./...` 通过。
|
||||
- 决策:样本全部脱敏,不提交本地真实身份证/姓名/电话;T-205 只建立映射测试基线,不扩展创建请求结构体。
|
||||
- 下一步:T-101(`osi/public.go` 四个字典查询)。
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-102 | `mapping/dict.go` 全量码表(含 56 项民族) | T-001 | 双向查表;未命中显式 ValidationError;单测覆盖(静态枚举,不走网络) | DONE |
|
||||
| T-202 | `mapping/health_record.go` + `mapping/checkid.go` | T-102, T-201 | 映射纯函数 + 结构化校验错误;主数据经 `MapContext` 字典快照注入(单测塞假快照);checkId 确定性生成单测 | DONE |
|
||||
| T-205 | 映射单测基线:docx 样例 + 联调样本 | T-202 | `go test ./mapping/...` 全绿;必填/码表/格式校验生效 | TODO |
|
||||
| T-205 | 映射单测基线:docx 样例 + 联调样本 | T-202 | `go test ./mapping/...` 全绿;必填/码表/格式校验生效 | DONE |
|
||||
|
||||
## Phase D · 字典服务与创建闭环(真实主数据反查)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user