Files
STM32F4-Base/docs/UI设计/UI_自动化测试流程.md
T
wandering1 c936441c83 门禁扩容:新增 lv-conf-sync、simulator/ 纳入全部钩子;含 L3 定值/元件框架落地
本轮把"自研代码落在门禁之外"的口子收掉,同时落地 LVGL 特性裁剪与
L3 保护定值/元件框架。

门禁(.pre-commit-config.yaml,26 个钩子)
- 新增 scripts/check_lv_conf_sync.py + 钩子 lv-conf-sync:比对两份
  lv_conf.h 的**生效值**(未定义则取 lv_conf_internal.h 兜底默认),
  抓 MISMATCH / LVGL 不认的宏名 / 同文件重复定义
- 顶层 exclude 删掉 simulator/:其下 21 个 tracked 文件全是本项目自研
  代码,生成物(build/、SDL2/、tests/ref/、shot*)已在 .gitignore;
  doc-links 的 exclude 同步删除
- lv-conf-sync 的 files: 覆盖两端配置 → 只改 simulator/lv_conf.h 也触发
  (pre-commit 4.x 已移除 always: true,实测只告警并跳过,无兜底开关)
- 新增 prot-set-unit-test / prot-elm-unit-test 两个主机侧单测钩子
- S11(2.3.5) 判定细化:禁的是"用路径找文件",尖括号系统头带子目录
  (如 <sys/stat.h>)不再误报;全仓库复核仅 2 处项目代码判定变化

模拟器代码整改(纳入钩子后暴露,全部修代码而非豁免)
- cppcheck 4 处:sim_syslog.c 判空分支内解引用 p_epoch(真实 bug)、
  2 处 struct tm 未初始化、1 处指针可加 const
- coding-standard 61 处:44 处函数左大括号并到右括号同行、8 处补函数
  注释、3 处补文件头注释块、2 处 __ 前缀保护宏改 XXX_H、2 处 sprintf
  改 snprintf(写入字节数与原来完全一致)

LVGL 特性裁剪(F-1/F-2/F-3)
- 两端 lv_conf.h 对齐同一特性子集:删 26 个 LVGL 9.3 不存在的选项名、
  3 处重复定义,10 项靠默认值隐式生效的改为显式固化
- 实测对镜像体积中性;价值在防漂移,且模拟器 golden 回归跑的正是固件
  实际编译的配置

L3 软件侧
- App/algo/prot_set.* Q10 定值模型(范围校验 / 整表 all-or-nothing /
  校验和封存-自检-闭锁)+ prot_elm.* 通用"滞回+定时限"元件框架 7 实例
- test/host/prot_set、test/host/prot_elm 主机侧单测;uvprojx 挂载两处

文档同步
- pre-commit使用说明:§2.8 S11 口径、§2.15 lv-conf-sync 详解、新增 §5.5
  复盘(教训:exclude 只写真正不该进钩子的路径)
- AGENTS.md、UI_设计架构 §1.4 第 10 条、RAM 分析、审查报告刷新与销项

验证
- @build BUILD_OK 0/0(Code=194276 RO=15872 RW=876 ZI=139892)
- 模拟器重建:菜单 8 状态像素逐字节一致(池 5368 B)、11 内容页黄金参考
  全过(往返 5448 B)、remo sink 0/25600 位差异、--logtest/--cfgtest PASS
- 全仓库 cppcheck / coding-standard / no-mojibake --all-files 全过
- check_doc_links --all 129/0;check_mem_numbers --check 内存数字一致
- 端到端:往 simulator/lv_conf.h 注入一行漂移 → 钩子 FAIL(exit 1)
2026-10-11 08:48:49 +08:00

9.2 KiB
Raw Blame History

UI 自动化测试流程(模拟器回归)

用途:所有涉及 UI 的改动(菜单结构 / 内容页 / 字体 / 样式 / 几何)改完代码后,按本文跑一遍全部门禁再提交。脚本已入库,直接调用即可,无需临时重写。 定位:UI_界面制作流程.md P2/P3 门禁的可执行版本;设计阶段(P0 规格 / P1 编码)走 UI_界面制作流程.md。


一、前置条件

项 说明
模拟器已构建 仓库根目录:& "simulator\build_sim.bat"(自动探测本机 VS2019/2022/2026 生成器,见 simulator/README.md §3.2)
Python 统一入口 .venv\Scripts\python.exe(AGENTS.md「Python 环境」);两个回归脚本纯标准库,任意 python3 均可,为保持一致一律用 .venv

二、流程总览

# 仓库根目录执行(python 统一用 .venv,见 AGENTS.md「Python 环境」)
cmake --build simulator/build --config Debug   # 0) 构建模拟器(须 0 警告)
.venv\Scripts\python.exe simulator/tests/check_menu_rows.py      # 1) 菜单 8 状态像素回归 + 池基线门禁
.venv\Scripts\python.exe simulator/tests/check_content_pages.py  # 2) 内容页黄金参考回归 + 往返池门禁
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py   # 3) Keil 构建(BUILD_OK,0 错 0 警)
.venv\Scripts\python.exe scripts/check_coding_standard.py        # 4) 代码规范机械检查(PASS)
步 脚本/命令 门禁内容 预期输出
1 simulator/tests/check_menu_rows.py 菜单 8 状态:选中行白带 / 非选行黑底白字 / 框体 1px 边框 / 往返像素一致(S3==S1、S6==S1、S7==S2)+ S0 池基线 PASS: 8 状态全部断言通过(8 图,池基线 5368 B)
2 simulator/tests/check_content_pages.py ① 文本级断言(字形模板匹配,50 条,独立于 ref/)→ ② 11 页截图与 ref/ 黄金参考逐字节比对 + 开页-关页往返池水位 PASS: 11 内容页 + 往返池水位全部通过(文本断言先于像素比对,失败即中止)
3 keil-build skill(keil_build.py) MCU 端编译(UI 源码双端共用,改一端必须过另一端) 退出码 0 = BUILD_OK
4 scripts/check_coding_standard.py 代码规范 V1.0 机械检查 PASS

文本级断言层(2026-09-10 新增):check_content_pages.py 内置字形模板匹配——直接解析 ui_font_cn_12.c 的 cmap/glyph_dsc/bitmap,把期望字符串(标题/标签/值/页脚,含新增易缺字文案) 渲染成墨点集合,在截图对应 y 带内做精确匹配(LVGL 基线对齐)。价值:缺字显示空白 / 标签写错 这类回归不再只靠像素位图(那需要刷参考,且无视觉后端时难以判读);文本断言不依赖 ref/,且 先于像素比对运行,失败即中止(不误刷参考)。文本断言覆盖确定文案,像素参考仍负责几何/样式/ 光标反显等其余视觉。

退出码约定:两个脚本均为 0=PASS / 1=断言失败 / 2=环境错误(exe 缺失、参考缺失)。 失败时脚本打印差异明细(文本断言未命中项 / ink runs 对照 / 像素差数),内容页脚本保留现场截图于临时目录并提示路径。

三、内存水位门禁常量

常量 所在脚本 当前值 含义
MENU_POOL_BASELINE check_menu_rows.py 5368 B 菜单根框建完的 LVGL 池 used(x64 模拟器)
POOL_AFTER_ROUNDTRIP check_content_pages.py 5448 B 开页-关页往返后水位 = 基线 + 一次性残留 80 B

水位历史:4784 →(2026-09-14 待机模块常驻 +656)5440 / 5520 →(2026-10-11 裁剪 LVGL 控件类 −72)5368 / 5448。 后一次漂移已核实为有意且更优:像素逐字节未变(11 页黄金参考在裁剪前生成、裁剪后全部一致), 且一次性残留仍是 80 B(5448 − 5368)→ 泄漏特征未变,只是 lv_theme_apply 不再为已不存在的控件类登记样式条目。

漂移处理:菜单/页面结构或样式变更导致门禁失败时,先确认新值合理(残留分解见 菜单页面设计.md §9.5),再更新脚本常量并在本文变更记录登记。禁止为过门禁盲目改常量—— 无法解释的漂移 = 内存回归 bug。

四、黄金参考与目检 PNG(均为本地生成物,不入库)

simulator/tests/ref/ 下的 .bin(像素黄金参考)与 .png(目检图)都不入库(.gitignore)—— 首次/换机后必须先生成一次:

.venv\Scripts\python.exe simulator/tests/check_content_pages.py --update   # 生成 ref/*.bin
.venv\Scripts\python.exe simulator/tests/regen_ref_png.py                  # 生成 ref/*.png(--scale 6 --invert)

有意改视觉时的流程:

  1. 先肉眼确认新效果正确:窗口模式运行 simulator\build\Debug\lvgl_sim.exe,或刷新后跑 regen_ref_png.py 看图对照 mockup;
  2. 刷新参考:.venv\Scripts\python.exe simulator/tests/check_content_pages.py --update(重写 ref/*.bin);
  3. 重生成目检 PNG:.venv\Scripts\python.exe simulator/tests/regen_ref_png.py。 .png 是本地调试产物、不会随 .bin 自动更新——不重跑则 PNG 仍是旧渲染(缺字/错位,看似"乱码")。 默认 --scale 6 --invert(深字白底便于目检);--no-invert = 白字黑底(与设备一致);
  4. 无需提交 ref/(已 gitignore)。

误刷保护:--update 会先跑文本级断言,断言失败即中止,避免把缺字/错标签的渲染"刷成"新基准。

何时不该更新:未有意改视觉而某页 FAIL → 是 bug(缺字、几何漂移、样式回归),修代码而不是刷参考。 菜单状态无黄金参考文件——其断言是结构性的(白带占比/边框/往返一致),不依赖入库位图。

五、误报排查

现象 常见原因与处置
多页大面积像素差异 字体重生成(ui_font_cn_12.c 变化)→ 确认字形正确后 --update 刷参考
单行/单字差异 几何或文案变更 → 先判断是否有意修改;无意 = bug
池水位门禁失败但像素一致 样式/结构变更(如动态样式转常量、增删框体)→ 确认新值合理后更新常量并登记
找不到 lvgl_sim.exe 模拟器未构建或 build/ 被删 → 先按 §一 重建
终端输出中文乱码 PowerShell 代码页渲染问题,不影响判定(看 PASS/FAIL 与退出码)

六、与其他文档的关系

  • UI_界面制作流程.md:P0 需求录入 + 设计规格 → P1 规格→代码 → P2 本文回归 → P3 MCU 上机目检 → P4 归档
  • 菜单页面设计.md §9:内容页对象树 / 几何表 / 内存预算(本文数字的来源)
  • simulator/README.md §3.5/§3.6:无头模式(--keys/--screenshot)与回归脚本说明

变更记录

日期 变更
2026-09-09 Python 解释器统一为仓库 .venv(新增 requirements.txt,.gitignore 忽略 .venv/);§1/§2/§4 命令同步改用 .venv\Scripts\python.exe
2026-09-09 初版:菜单 8 状态像素回归 + 内容页黄金参考回归(ref/ 3 图,I1 原始位图入库)+ 池水位门禁(4784/4864 B)。脚本自会话临时目录整理入 simulator/tests/(相对路径定位 exe、输出改临时目录),替代每次重写
2026-09-10 check_content_pages.py 新增文本级断言层(字形模板匹配 50 条,独立于 ref/,先于像素比对运行、失败即中止防误刷参考);内容页扩至 11 页(+网口设置 4 态);§二/§四同步
2026-09-10 新增 simulator/tests/regen_ref_png.py(由 ref/*.bin 批量重生成目检 PNG,默认 --scale 6 --invert);ref/*.png 加入 .gitignore(本地调试产物不入库);§四 补"重生成目检 PNG"步骤(修复"刷了 .bin 参考但 .png 仍是旧渲染 → 看似乱码")
2026-09-10 simulator/tests/ref/ 整目录不入库(.bin 黄金参考 + .png 目检图均为本地生成物):git rm --cached 原有 3 个 .bin,.gitignore 改为忽略整目录;首次/换机后先 --update 生成参考;--update 先跑文本断言防误刷;§四 重写
2026-09-13 管线同步:UI_界面制作流程.md 移除 HTML 样机阶段(五阶段 → 四阶段 P0~P4),本文定位改为"P2/P3 门禁的可执行版本";§六 关系描述更新为 P0 规格 → P1 编码 → P2 本文回归 → P3 上机目检 → P4 归档;移除 tools/ui_mock/ 引用
2026-10-11 裁剪 LVGL 死代码(F-1/F-2/F-3)时的门禁记录:先用未裁剪配置 --update 生成 11 页黄金参考,再切到裁剪配置重编重跑 → 逐字节全部一致(菜单 8 状态像素一致),证明裁剪零视觉影响。池水位门禁随之 5440/5520 → 5368/5448(−72 B;一次性残留仍 80 B,故非泄漏变化,见 §三 水位历史)。顺带揪出并修掉 Lib/lv_conf.h 与 simulator/lv_conf.h 的长期漂移(模拟器早已 I1-only、MCU 端未裁)→ 规则见 UI_设计架构.md §1.4 第 10 条,量化见 ../内存管理/RAM使用分析与优化方案.md §2.6.4