4. 自动化测试基础

在嵌入式UI项目中,自动化测试并不是“写几个脚本跑一跑”这么简单。它需要一套分层策略:哪些逻辑用单元测试快速验证,哪些接口用集成测试保证协作正确,哪些场景必须放到系统测试或UI测试中验证。理解测试金字塔,是建立可持续测试体系的第一步。

一、测试金字塔:分层投入与反馈速度

测试金字塔由Mike Cohn提出,核心思想是:底层测试数量多、执行快、成本低;上层测试数量少、执行慢、成本高。对于嵌入式UI,底层通常是纯逻辑与协议解析,中层是模块间接口与驱动交互,顶层是整机行为与UI操作。

UI测试 少而精 · 慢 · 高成本 系统测试 端到端场景 · 中速 集成测试 接口与驱动协作 · 较快 单元测试 多而快 · 低成本 · 反馈秒级 反馈速度 慢 ↑ 快 ↓

金字塔不是“必须严格按比例”,而是提醒我们:如果UI测试数量远超单元测试,测试套件会变得又慢又脆。嵌入式UI常见的反模式是“所有验证都靠上电后点屏幕”,结果每次回归要几十分钟,失败原因还难以定位。

二、五类测试的区别与联系

单元测试针对最小可测单元,通常是纯函数、状态机、协议编解码、UI数据绑定逻辑。它不依赖真实硬件,用桩或模拟替代外部依赖,执行时间在毫秒级。集成测试验证两个或多个模块组合后的行为,例如触摸驱动与事件分发、显示驱动与帧缓冲、通信协议与业务解析。系统测试从整机角度验证功能与非功能需求,如开机流程、页面切换、告警响应、低功耗唤醒。UI测试则模拟用户操作,验证控件布局、触摸响应、动画与多语言显示。

测试类型 验证对象 典型工具/手段 执行速度 失败定位难度
单元测试 函数、状态机、解析逻辑 Unity、GoogleTest、pytest 毫秒级 低
集成测试 模块接口、驱动与中间件 Mock驱动、仿真器、桩函数 秒级 中
系统测试 整机功能、性能、功耗 硬件在环、自动化脚本 分钟级 较高
UI测试 控件、触摸、视觉呈现 Appium、SikuliX、LVGL模拟器 分钟级 高

它们的联系在于“同一需求在不同层次被反复验证”。例如“点击按钮后LED亮起”:单元测试验证按钮事件处理函数返回正确状态;集成测试验证GPIO驱动被正确调用;系统测试验证真实LED亮起;UI测试验证按钮可点击且无遮挡。层次越往上,越接近用户价值,但反馈越慢、维护成本越高。

三、TDD简介:先写测试,再写实现

测试驱动开发(TDD)的核心循环是“红—绿—重构”:先写一个失败的测试(红),再写最少代码让测试通过(绿),最后在测试保护下重构。对嵌入式UI而言,TDD特别适合纯逻辑层,例如页面状态机、菜单导航、数据格式化、协议解析。

// 示例:LVGL页面状态机TDD片段(伪代码)
TEST(PageState, switch_to_settings_when_click_settings) {
    page_state_init();
    page_state_handle_event(EVENT_CLICK_SETTINGS);
    ASSERT_EQ(page_state_current(), PAGE_SETTINGS);
}
// 先运行:失败(红)
// 实现page_state_handle_event后:通过(绿)
// 再重构事件表,测试仍通过
TDD不是“测试优先”的口号,而是一种设计方法。它迫使你在写实现前想清楚接口、输入输出和边界条件,从而减少过度设计。

四、案例与误区复盘

某智能面板项目初期只做UI自动化,每次回归需25分钟,且经常因动画时序失败。后来团队将协议解析、页面状态机下沉为单元测试,把驱动交互改为集成测试,UI测试只保留8条核心路径。结果回归时间降到6分钟,失败定位从“看截图猜”变成“直接看断言”。

常见误区:1)认为单元测试“没价值”,只测UI;2)集成测试中大量使用真实硬件,导致无法在CI中并行;3)UI测试追求覆盖率,却忽略稳定性;4)TDD只写测试不重构,测试变成实现细节的复制。

建议的实践顺序是:先为纯逻辑建立单元测试,再为关键接口建立集成测试,然后用系统测试覆盖开机、通信、告警等端到端场景,最后用少量UI测试守住用户可见的关键路径。每一层都应有明确的通过标准和失败回滚策略,并与CI流水线绑定,让测试金字塔真正支撑嵌入式UI的持续集成。