This commit is contained in:
quyixiao 2026-06-06 01:54:46 +08:00
parent 6da6f778e3
commit 1ff0df6cdb
3 changed files with 869 additions and 0 deletions

View File

@ -0,0 +1,600 @@
# RecognizeDriverLicenseController 测试报告
## 测试环境
| 项 | 值 |
|---|---|
| 测试时间 | 2026-06-06 01:51:54 |
| 服务地址 | `http://localhost:8888` |
| 接口路径 | `POST /driver/license/recognize` |
| Content-Type | `application/json` |
| 鉴权 | macOS 本地环境跳过 Tencent 鉴权LogAop 非 Linux 不拦截) |
## 汇总
- 总用例:**19**
- 通过:**19**
- 失败:**0**
- 通过率:**100%**
## 用例明细
| 编号 | 场景 | 类型 | HTTP | code | 结果 | 说明 |
|---|---|---|---|---|---|---|
| TC01 | 缺少 imageUrlOrBase64 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC02 | imageUrlOrBase64 空字符串 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC03 | imageUrlOrBase64 仅空白 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC04 | side 非法值 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC05 | www 缺少协议头 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC06 | ftp 协议 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC07 | Unix 本地路径 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC08 | Windows 本地路径 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC09 | 非 Base64 普通文本 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC10 | data 前缀缺少 base64 段 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC11 | Base64 过短 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC12 | Base64 填充位非法 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC13 | http 协议少斜杠 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC14 | 双斜杠缺协议 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC15 | file 协议 | 入参校验 | 200 | 200 | ✅ 通过 | 入参校验拦截成功,返回 R.ok + 提示 |
| TC16 | 有效 HTTPS 公网图片(正页) | 平台识别 | 200 | 200 | ✅ 通过 | 平台链路返回提示:平台业务拒绝 |
| TC17 | 有效 1x1 PNG Base64 | 平台识别 | 200 | 200 | ✅ 通过 | 平台链路返回提示:影像不合规 |
| TC18 | side=back 公网图片 | 平台识别 | 200 | 200 | ✅ 通过 | 平台链路返回提示:平台业务拒绝 |
| TC19 | side=front 别名 | 平台识别 | 200 | 200 | ✅ 通过 | 平台链路返回提示:并发限流 |
## 详细记录
### TC01 缺少 imageUrlOrBase64
- **类型**:入参校验
- **期望**:影像源缺失
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串
```
**响应 data摘要**
```json
{}
```
### TC02 imageUrlOrBase64 空字符串
- **类型**:入参校验
- **期望**:影像源缺失
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串
```
**响应 data摘要**
```json
{}
```
### TC03 imageUrlOrBase64 仅空白
- **类型**:入参校验
- **期望**:影像源缺失
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": " ",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串
```
**响应 data摘要**
```json
{}
```
### TC04 side 非法值
- **类型**:入参校验
- **期望**:页面标识无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "https://example.com/a.jpg",
"side": "invalid"
}
```
**响应 msg**
```
【驾驶证识别·页面标识无效】参数 side 的取值无法映射到驾驶证正页或副页识别模式|定位信息:当前 side=invalid合法取值=face|front|back处置指引正页含纸质正页、电子驾驶证正页请传 face 或 front副页含实习记录等请传 back
```
**响应 data摘要**
```json
{}
```
### TC05 www 缺少协议头
- **类型**:入参校验
- **期望**:链接缺少协议头
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "www.example.com/a.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·链接缺少协议头】链接以 www. 开头但缺少协议头,无法识别为 HTTP(S) 地址|定位信息:入参前缀=www.example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头
```
**响应 data摘要**
```json
{}
```
### TC06 ftp 协议
- **类型**:入参校验
- **期望**:链接协议无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "ftp://example.com/a.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·链接协议无效】检测到 ftp:// 协议,本接口仅支持 HTTP/HTTPS 图片链接|定位信息:入参前缀=ftp://example.com/a.jpgside=face处置指引图片链接须以 http:// 或 https:// 开头,且可被公网访问
```
**响应 data摘要**
```json
{}
```
### TC07 Unix 本地路径
- **类型**:入参校验
- **期望**:影像格式无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "/tmp/driver.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像格式无效】检测到以 / 开头的本地绝对路径,无法作为网络图片链接使用|定位信息:入参前缀=/tmp/driver.jpgside=face处置指引请改为 HTTP/HTTPS 图片链接,或将图片转为 Base64 后传入
```
**响应 data摘要**
```json
{}
```
### TC08 Windows 本地路径
- **类型**:入参校验
- **期望**:影像格式无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "C:\\images\\driver.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像格式无效】检测到 Windows 本地路径(如 C:\...),无法作为网络图片链接使用|定位信息:入参前缀=C:\images\driver.jpgside=face处置指引请改为 HTTP/HTTPS 图片链接,或将图片转为 Base64 后传入
```
**响应 data摘要**
```json
{}
```
### TC09 非 Base64 普通文本
- **类型**:入参校验
- **期望**Base64 字符非法
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "not-a-valid-image-input",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·Base64 字符非法】内容包含非 Base64 合法字符(仅允许 A-Z、a-z、0-9、+、/、=)|定位信息:非法片段示例=not-a-vaside=face处置指引请检查是否误传了普通文本、JSON 字段名或文件路径;链接须以 http:// 或 https:// 开头
```
**响应 data摘要**
```json
{}
```
### TC10 data 前缀缺少 base64 段
- **类型**:入参校验
- **期望**Base64 前缀无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "data:image/jpeg;xxx,abc",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·Base64 前缀无效】data: 前缀格式不正确,缺少 base64, 段|定位信息:入参前缀=data:image/jpeg;xxx,abcside=face处置指引请使用 data:image/jpeg;base64,{数据} 格式,或直接传纯 Base64 字符串
```
**响应 data摘要**
```json
{}
```
### TC11 Base64 过短
- **类型**:入参校验
- **期望**Base64 内容过短
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "abc",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·Base64 内容过短】剥离前缀后 Base64 仅 3 字符,不足以构成有效图片|定位信息:原始入参长度=3 字符side=face处置指引请确认图片已完整编码未截断
```
**响应 data摘要**
```json
{}
```
### TC12 Base64 填充位非法
- **类型**:入参校验
- **期望**Base64 字符非法
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "abcd====",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·Base64 字符非法】内容包含非 Base64 合法字符(仅允许 A-Z、a-z、0-9、+、/、=)|定位信息:非法片段示例=abcd====side=face处置指引请检查是否误传了普通文本、JSON 字段名或文件路径;链接须以 http:// 或 https:// 开头
```
**响应 data摘要**
```json
{}
```
### TC13 http 协议少斜杠
- **类型**:入参校验
- **期望**:链接缺少协议头
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "http:/example.com/a.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·链接缺少协议头】链接协议写法错误,应为 http:// 而非 http:/|定位信息:入参前缀=http:/example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头
```
**响应 data摘要**
```json
{}
```
### TC14 双斜杠缺协议
- **类型**:入参校验
- **期望**:链接缺少协议头
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "//example.com/a.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·链接缺少协议头】链接以 // 开头但缺少协议头(如 https:),无法识别为完整 URL定位信息入参前缀=//example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头
```
**响应 data摘要**
```json
{}
```
### TC15 file 协议
- **类型**:入参校验
- **期望**:链接协议无效
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 入参校验拦截成功,返回 R.ok + 提示
**请求体:**
```json
{
"imageUrlOrBase64": "file:///tmp/a.jpg",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·链接协议无效】检测到 file:// 本地文件协议,不支持直接读取本地文件|定位信息:入参前缀=file:///tmp/a.jpgside=face处置指引图片链接须以 http:// 或 https:// 开头,且可被公网访问
```
**响应 data摘要**
```json
{}
```
### TC16 有效 HTTPS 公网图片(正页)
- **类型**:平台识别
- **期望**:进入平台识别链路
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 平台链路返回提示:平台业务拒绝
**请求体:**
```json
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·平台业务拒绝】平台返回了未在本地维护的错误码,需结合错误描述人工判读|定位信息:错误码=282103错误描述=recognize error, failed to match the template目标页面=正页(front/face)|处置指引:请依据错误描述调整入参或影像后重试;持续失败请附带 traceId 联系技术支持
```
**响应 data摘要**
```json
{}
```
### TC17 有效 1x1 PNG Base64
- **类型**:平台识别
- **期望**:进入平台识别链路
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 平台链路返回提示:影像不合规
**请求体:**
```json
{
"imageUrlOrBase64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
"side": "face"
}
```
**响应 msg**
```
【驾驶证识别·影像不合规】像素尺寸或编码后体积不满足规范(边长 15~4096px编码后≤4M定位信息错误码=216202错误描述=image size error目标页面=正页(front/face)处置指引请压缩或裁剪图片保证最长边≤4096px、最短边≥15px且 urlencode 后≤4M
```
**响应 data摘要**
```json
{}
```
### TC18 side=back 公网图片
- **类型**:平台识别
- **期望**:进入平台识别链路
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 平台链路返回提示:平台业务拒绝
**请求体:**
```json
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "back"
}
```
**响应 msg**
```
【驾驶证识别·平台业务拒绝】平台返回了未在本地维护的错误码,需结合错误描述人工判读|定位信息:错误码=282103错误描述=recognize error, failed to match the template目标页面=副页(back)|处置指引:请依据错误描述调整入参或影像后重试;持续失败请附带 traceId 联系技术支持
```
**响应 data摘要**
```json
{}
```
### TC19 side=front 别名
- **类型**:平台识别
- **期望**:进入平台识别链路
- **HTTP 状态码**200
- **业务 code**`200`
- **结果**:通过 — 平台链路返回提示:并发限流
**请求体:**
```json
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "front"
}
```
**响应 msg**
```
【驾驶证识别·并发限流】单位时间请求过于密集,已触发平台 QPS 限流,请拉长调用间隔后重试|定位信息:错误码=18错误描述=Open api qps request limit reached目标页面=正页(front/face)|处置指引:请在客户端增加限流/退避策略,避免瞬时并发过高
```
**响应 data摘要**
```json
{}
```
## 结论
1. **入参校验类用例TC01TC15**:均返回 HTTP 200 + 业务 code 200错误说明写入 `msg``data` 为空对象,符合「校验失败也返回 ok」的约定。
2. **平台识别类用例TC16TC19**:使用公网 PNG / 1x1 Base64 触发百度识别链路;测试图非驾驶证,字段为空或带平台提示属正常。
3. **建议**:补充真实驾驶证正/副页样本,验证字段映射完整性。

View File

@ -0,0 +1,250 @@
#!/usr/bin/env python3
"""RecognizeDriverLicenseController 本地接口测试脚本。"""
import json
import urllib.request
from datetime import datetime
from pathlib import Path
BASE_URL = "http://localhost:8888/driver/license/recognize"
OUT_DIR = Path(__file__).parent
RESULTS_FILE = OUT_DIR / "test_results.jsonl"
REPORT_FILE = OUT_DIR / "TEST_REPORT.md"
CASES = [
("TC01", "缺少 imageUrlOrBase64", {"side": "face"}, "入参校验", "影像源缺失"),
("TC02", "imageUrlOrBase64 空字符串", {"imageUrlOrBase64": "", "side": "face"}, "入参校验", "影像源缺失"),
("TC03", "imageUrlOrBase64 仅空白", {"imageUrlOrBase64": " ", "side": "face"}, "入参校验", "影像源缺失"),
("TC04", "side 非法值", {"imageUrlOrBase64": "https://example.com/a.jpg", "side": "invalid"}, "入参校验", "页面标识无效"),
("TC05", "www 缺少协议头", {"imageUrlOrBase64": "www.example.com/a.jpg", "side": "face"}, "入参校验", "链接缺少协议头"),
("TC06", "ftp 协议", {"imageUrlOrBase64": "ftp://example.com/a.jpg", "side": "face"}, "入参校验", "链接协议无效"),
("TC07", "Unix 本地路径", {"imageUrlOrBase64": "/tmp/driver.jpg", "side": "face"}, "入参校验", "影像格式无效"),
("TC08", "Windows 本地路径", {"imageUrlOrBase64": r"C:\images\driver.jpg", "side": "face"}, "入参校验", "影像格式无效"),
("TC09", "非 Base64 普通文本", {"imageUrlOrBase64": "not-a-valid-image-input", "side": "face"}, "入参校验", "Base64 字符非法"),
("TC10", "data 前缀缺少 base64 段", {"imageUrlOrBase64": "data:image/jpeg;xxx,abc", "side": "face"}, "入参校验", "Base64 前缀无效"),
("TC11", "Base64 过短", {"imageUrlOrBase64": "abc", "side": "face"}, "入参校验", "Base64 内容过短"),
("TC12", "Base64 填充位非法", {"imageUrlOrBase64": "abcd====", "side": "face"}, "入参校验", "Base64 字符非法"),
("TC13", "http 协议少斜杠", {"imageUrlOrBase64": "http:/example.com/a.jpg", "side": "face"}, "入参校验", "链接缺少协议头"),
("TC14", "双斜杠缺协议", {"imageUrlOrBase64": "//example.com/a.jpg", "side": "face"}, "入参校验", "链接缺少协议头"),
("TC15", "file 协议", {"imageUrlOrBase64": "file:///tmp/a.jpg", "side": "face"}, "入参校验", "链接协议无效"),
(
"TC16",
"有效 HTTPS 公网图片(正页)",
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "face",
},
"平台识别",
None,
),
(
"TC17",
"有效 1x1 PNG Base64",
{
"imageUrlOrBase64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
"side": "face",
},
"平台识别",
None,
),
(
"TC18",
"side=back 公网图片",
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "back",
},
"平台识别",
None,
),
(
"TC19",
"side=front 别名",
{
"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png",
"side": "front",
},
"平台识别",
None,
),
]
def call_api(payload: dict) -> tuple[int, dict]:
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(
BASE_URL,
data=data,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=60) as resp:
body = json.loads(resp.read().decode("utf-8"))
return resp.status, body
def extract_category(msg: str) -> str:
if not msg:
return ""
if "【驾驶证识别·" in msg and "" in msg:
return msg.split("【驾驶证识别·", 1)[1].split("", 1)[0]
return ""
def count_filled_fields(data: dict) -> int:
if not isinstance(data, dict):
return 0
return sum(1 for v in data.values() if isinstance(v, str) and v.strip())
def evaluate(case_id, expected_hint, response):
code = str(response.get("code", ""))
msg = response.get("msg") or ""
category = extract_category(msg)
if code != "200":
return False, f"code 期望 200实际 {code}"
input_validation_categories = {
"影像源缺失", "页面标识无效", "链接缺少协议头", "链接协议无效", "影像格式无效",
"Base64 前缀无效", "Base64 内容过短", "Base64 字符非法", "Base64 解码失败",
"Base64 体积过大", "链接过长", "链接解析失败", "入参绑定失败",
}
if expected_hint:
if expected_hint not in msg:
return False, f"msg 未包含期望分类「{expected_hint}」,实际分类「{category}"
return True, "入参校验拦截成功,返回 R.ok + 提示"
if category:
if category in input_validation_categories:
return False, f"期望进入平台识别,但仍在入参校验阶段:{category}"
return True, f"平台链路返回提示:{category}"
if count_filled_fields(response.get("data") or {}) > 0:
return True, "平台识别成功,返回结构化字段"
return True, "平台返回成功data 字段为空(测试图非驾驶证,符合预期)"
def build_report(results: list[dict]) -> str:
passed = sum(1 for r in results if r["passed"])
failed = len(results) - passed
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
lines = [
"# RecognizeDriverLicenseController 测试报告",
"",
"## 测试环境",
"",
"| 项 | 值 |",
"|---|---|",
f"| 测试时间 | {now} |",
"| 服务地址 | `http://localhost:8888` |",
"| 接口路径 | `POST /driver/license/recognize` |",
"| Content-Type | `application/json` |",
"| 鉴权 | macOS 本地环境跳过 Tencent 鉴权LogAop 非 Linux 不拦截) |",
"",
"## 汇总",
"",
f"- 总用例:**{len(results)}**",
f"- 通过:**{passed}**",
f"- 失败:**{failed}**",
f"- 通过率:**{passed * 100 // len(results)}%**",
"",
"## 用例明细",
"",
"| 编号 | 场景 | 类型 | HTTP | code | 结果 | 说明 |",
"|---|---|---|---|---|---|---|",
]
for r in results:
status = "✅ 通过" if r["passed"] else "❌ 失败"
msg_short = (r["response"].get("msg") or "(无提示)")[:60].replace("|", "/")
lines.append(
f"| {r['id']} | {r['name']} | {r['type']} | {r['httpCode']} | "
f"{r['response'].get('code', '')} | {status} | {r['verdict']} |"
)
lines.extend(["", "## 详细记录", ""])
for r in results:
lines.extend(
[
f"### {r['id']} {r['name']}",
"",
f"- **类型**{r['type']}",
f"- **期望**{r['expect']}",
f"- **HTTP 状态码**{r['httpCode']}",
f"- **业务 code**`{r['response'].get('code', '')}`",
f"- **结果**{'通过' if r['passed'] else '失败'}{r['verdict']}",
"",
"**请求体:**",
"",
"```json",
json.dumps(r["request"], ensure_ascii=False, indent=2),
"```",
"",
"**响应 msg**",
"",
"```",
r["response"].get("msg") or "(空)",
"```",
"",
"**响应 data摘要**",
"",
"```json",
json.dumps(r["response"].get("data"), ensure_ascii=False, indent=2),
"```",
"",
]
)
lines.extend(
[
"## 结论",
"",
"1. **入参校验类用例TC01TC15**:均返回 HTTP 200 + 业务 code 200错误说明写入 `msg``data` 为空对象,符合「校验失败也返回 ok」的约定。",
"2. **平台识别类用例TC16TC19**:使用公网 PNG / 1x1 Base64 触发百度识别链路;测试图非驾驶证,字段为空或带平台提示属正常。",
"3. **建议**:补充真实驾驶证正/副页样本,验证字段映射完整性。",
"",
]
)
return "\n".join(lines)
def main() -> None:
results = []
RESULTS_FILE.write_text("", encoding="utf-8")
for case_id, name, payload, case_type, expected_hint in CASES:
try:
http_code, response = call_api(payload)
passed, verdict = evaluate(case_id, expected_hint, response)
error = None
except Exception as exc: # noqa: BLE001
http_code, response = 0, {"code": "error", "msg": str(exc), "data": {}}
passed, verdict = False, f"请求异常:{exc}"
error = str(exc)
entry = {
"id": case_id,
"name": name,
"type": case_type,
"request": payload,
"httpCode": http_code,
"response": response,
"expect": expected_hint or "进入平台识别链路",
"passed": passed,
"verdict": verdict,
"error": error,
}
results.append(entry)
with RESULTS_FILE.open("a", encoding="utf-8") as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
print(f"{case_id} {'PASS' if passed else 'FAIL'} - {verdict}")
REPORT_FILE.write_text(build_report(results), encoding="utf-8")
print(f"\nReport written to: {REPORT_FILE}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,19 @@
{"id": "TC01", "name": "缺少 imageUrlOrBase64", "type": "入参校验", "request": {"side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串", "traceId": "on10048420260606015153"}, "expect": "影像源缺失", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC02", "name": "imageUrlOrBase64 空字符串", "type": "入参校验", "request": {"imageUrlOrBase64": "", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串", "traceId": "on84448620260606015153"}, "expect": "影像源缺失", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC03", "name": "imageUrlOrBase64 仅空白", "type": "入参校验", "request": {"imageUrlOrBase64": " ", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像源缺失】imageUrlOrBase64 未提供或仅包含空白字符|定位信息:入参长度=0side=face处置指引请传 HTTP/HTTPS 图片链接,或 jpg/jpeg/png/bmp 的 Base64 字符串", "traceId": "on64248820260606015153"}, "expect": "影像源缺失", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC04", "name": "side 非法值", "type": "入参校验", "request": {"imageUrlOrBase64": "https://example.com/a.jpg", "side": "invalid"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·页面标识无效】参数 side 的取值无法映射到驾驶证正页或副页识别模式|定位信息:当前 side=invalid合法取值=face|front|back处置指引正页含纸质正页、电子驾驶证正页请传 face 或 front副页含实习记录等请传 back", "traceId": "on38349020260606015153"}, "expect": "页面标识无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC05", "name": "www 缺少协议头", "type": "入参校验", "request": {"imageUrlOrBase64": "www.example.com/a.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·链接缺少协议头】链接以 www. 开头但缺少协议头,无法识别为 HTTP(S) 地址|定位信息:入参前缀=www.example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头", "traceId": "on75749120260606015153"}, "expect": "链接缺少协议头", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC06", "name": "ftp 协议", "type": "入参校验", "request": {"imageUrlOrBase64": "ftp://example.com/a.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·链接协议无效】检测到 ftp:// 协议,本接口仅支持 HTTP/HTTPS 图片链接|定位信息:入参前缀=ftp://example.com/a.jpgside=face处置指引图片链接须以 http:// 或 https:// 开头,且可被公网访问", "traceId": "on79049320260606015153"}, "expect": "链接协议无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC07", "name": "Unix 本地路径", "type": "入参校验", "request": {"imageUrlOrBase64": "/tmp/driver.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像格式无效】检测到以 / 开头的本地绝对路径,无法作为网络图片链接使用|定位信息:入参前缀=/tmp/driver.jpgside=face处置指引请改为 HTTP/HTTPS 图片链接,或将图片转为 Base64 后传入", "traceId": "on19349420260606015153"}, "expect": "影像格式无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC08", "name": "Windows 本地路径", "type": "入参校验", "request": {"imageUrlOrBase64": "C:\\images\\driver.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像格式无效】检测到 Windows 本地路径(如 C:\\...),无法作为网络图片链接使用|定位信息:入参前缀=C:\\images\\driver.jpgside=face处置指引请改为 HTTP/HTTPS 图片链接,或将图片转为 Base64 后传入", "traceId": "on77849520260606015153"}, "expect": "影像格式无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC09", "name": "非 Base64 普通文本", "type": "入参校验", "request": {"imageUrlOrBase64": "not-a-valid-image-input", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·Base64 字符非法】内容包含非 Base64 合法字符(仅允许 A-Z、a-z、0-9、+、/、=)|定位信息:非法片段示例=not-a-vaside=face处置指引请检查是否误传了普通文本、JSON 字段名或文件路径;链接须以 http:// 或 https:// 开头", "traceId": "on77149720260606015153"}, "expect": "Base64 字符非法", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC10", "name": "data 前缀缺少 base64 段", "type": "入参校验", "request": {"imageUrlOrBase64": "data:image/jpeg;xxx,abc", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·Base64 前缀无效】data: 前缀格式不正确,缺少 base64, 段|定位信息:入参前缀=data:image/jpeg;xxx,abcside=face处置指引请使用 data:image/jpeg;base64,{数据} 格式,或直接传纯 Base64 字符串", "traceId": "on34149820260606015153"}, "expect": "Base64 前缀无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC11", "name": "Base64 过短", "type": "入参校验", "request": {"imageUrlOrBase64": "abc", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·Base64 内容过短】剥离前缀后 Base64 仅 3 字符,不足以构成有效图片|定位信息:原始入参长度=3 字符side=face处置指引请确认图片已完整编码未截断", "traceId": "on39249920260606015153"}, "expect": "Base64 内容过短", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC12", "name": "Base64 填充位非法", "type": "入参校验", "request": {"imageUrlOrBase64": "abcd====", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·Base64 字符非法】内容包含非 Base64 合法字符(仅允许 A-Z、a-z、0-9、+、/、=)|定位信息:非法片段示例=abcd====side=face处置指引请检查是否误传了普通文本、JSON 字段名或文件路径;链接须以 http:// 或 https:// 开头", "traceId": "on17850020260606015153"}, "expect": "Base64 字符非法", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC13", "name": "http 协议少斜杠", "type": "入参校验", "request": {"imageUrlOrBase64": "http:/example.com/a.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·链接缺少协议头】链接协议写法错误,应为 http:// 而非 http:/|定位信息:入参前缀=http:/example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头", "traceId": "on65750120260606015153"}, "expect": "链接缺少协议头", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC14", "name": "双斜杠缺协议", "type": "入参校验", "request": {"imageUrlOrBase64": "//example.com/a.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·链接缺少协议头】链接以 // 开头但缺少协议头(如 https:),无法识别为完整 URL定位信息入参前缀=//example.com/a.jpgside=face处置指引若以链接传图请补全为 https:// 或 http:// 开头", "traceId": "on25950220260606015153"}, "expect": "链接缺少协议头", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC15", "name": "file 协议", "type": "入参校验", "request": {"imageUrlOrBase64": "file:///tmp/a.jpg", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·链接协议无效】检测到 file:// 本地文件协议,不支持直接读取本地文件|定位信息:入参前缀=file:///tmp/a.jpgside=face处置指引图片链接须以 http:// 或 https:// 开头,且可被公网访问", "traceId": "on73850420260606015153"}, "expect": "链接协议无效", "passed": true, "verdict": "入参校验拦截成功,返回 R.ok + 提示", "error": null}
{"id": "TC16", "name": "有效 HTTPS 公网图片(正页)", "type": "平台识别", "request": {"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·平台业务拒绝】平台返回了未在本地维护的错误码,需结合错误描述人工判读|定位信息:错误码=282103错误描述=recognize error, failed to match the template目标页面=正页(front/face)|处置指引:请依据错误描述调整入参或影像后重试;持续失败请附带 traceId 联系技术支持", "traceId": "on70750520260606015153"}, "expect": "进入平台识别链路", "passed": true, "verdict": "平台链路返回提示:平台业务拒绝", "error": null}
{"id": "TC17", "name": "有效 1x1 PNG Base64", "type": "平台识别", "request": {"imageUrlOrBase64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", "side": "face"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·影像不合规】像素尺寸或编码后体积不满足规范(边长 15~4096px编码后≤4M定位信息错误码=216202错误描述=image size error目标页面=正页(front/face)处置指引请压缩或裁剪图片保证最长边≤4096px、最短边≥15px且 urlencode 后≤4M", "traceId": "on73109520260606015154"}, "expect": "进入平台识别链路", "passed": true, "verdict": "平台链路返回提示:影像不合规", "error": null}
{"id": "TC18", "name": "side=back 公网图片", "type": "平台识别", "request": {"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png", "side": "back"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·平台业务拒绝】平台返回了未在本地维护的错误码,需结合错误描述人工判读|定位信息:错误码=282103错误描述=recognize error, failed to match the template目标页面=副页(back)|处置指引:请依据错误描述调整入参或影像后重试;持续失败请附带 traceId 联系技术支持", "traceId": "on42619920260606015154"}, "expect": "进入平台识别链路", "passed": true, "verdict": "平台链路返回提示:平台业务拒绝", "error": null}
{"id": "TC19", "name": "side=front 别名", "type": "平台识别", "request": {"imageUrlOrBase64": "https://www.opsky.com.cn/upload/20211224/KXfgvm2MFRAXKbPu5LK.png", "side": "front"}, "httpCode": 200, "response": {"data": {}, "code": "200", "msg": "【驾驶证识别·并发限流】单位时间请求过于密集,已触发平台 QPS 限流,请拉长调用间隔后重试|定位信息:错误码=18错误描述=Open api qps request limit reached目标页面=正页(front/face)|处置指引:请在客户端增加限流/退避策略,避免瞬时并发过高", "traceId": "on92073220260606015154"}, "expect": "进入平台识别链路", "passed": true, "verdict": "平台链路返回提示:并发限流", "error": null}