3. 自动化测试框架设计原则
做ADAS测试这么多年,我见过太多团队一上来就撸代码写脚本。结果呢?三个月后,测试用例堆成了一团乱麻,换个传感器型号就得改半天的脚本。说白了,框架设计这件事,一开始没想清楚,后面全是坑。
今天我就把这些年总结的框架设计原则掰开揉碎讲给你听。嗯,这章内容有点干,但绝对值得你反复看几遍。
框架分层设计:四层架构
我个人习惯把自动化测试框架分成四层。为什么是四层?因为我在项目里试过三层,发现业务逻辑和数据混在一起,维护起来太痛苦。也试过五层,又觉得过度设计了。四层刚刚好。
| 层级 | 名称 | 核心职责 | 谁负责维护 |
|---|---|---|---|
| 第1层 | 测试用例层 | 描述测试场景和预期结果 | 测试工程师 |
| 第2层 | 业务逻辑层 | 封装ADAS功能操作步骤 | 测试开发工程师 |
| 第3层 | 数据驱动层 | 管理测试数据和参数配置 | 测试工程师 |
| 第4层 | 基础设施层 | 提供底层驱动和工具支持 | 自动化架构师 |
测试用例层
这一层离业务最近。你想想看,测试用例本质上就是「在什么条件下,做什么操作,期望什么结果」。我建议用例层只写业务描述,不要掺任何技术细节。
好的用例层写法:
# test_ACC_follow_stop_go.py
"""
场景:前车静止后重新起步,ACC应自动跟随
前置条件:ACC已激活,设定车速120km/h
步骤:
1. 前车以60km/h匀速行驶
2. 前车减速至0并保持3秒
3. 前车加速至30km/h
预期:本车自动跟随起步,保持安全时距
"""
我曾经见过一个团队把CAN信号配置直接写在用例里,结果换了台测试车,所有用例都得改。这就是典型的「层没分清楚」。
业务逻辑层
这一层是框架的核心。它把ADAS的各种功能拆解成可复用的操作单元。比如「激活ACC」、「设置跟车距离」、「模拟前车切入」这些,都应该封装成独立的方法。
我的经验:业务逻辑层的方法命名要像读说明书一样自然。比如 acc_activate()、lane_change_detect()。别用 func_a() 这种名字,三个月后你自己都看不懂。
数据驱动层
数据驱动说白了就是把「变的东西」和「不变的东西」分开。变的是测试数据,不变的是测试流程。
我建议用Excel或YAML管理测试数据。举个例子:
# test_data/ACC_follow.yaml
test_cases:
- id: TC_ACC_001
description: "前车匀速,ACC跟随"
ego_speed: 80
target_speed: 60
distance: 50
expected: "保持安全时距"
- id: TC_ACC_002
description: "前车减速,ACC响应"
ego_speed: 100
target_speed: 40
distance: 80
expected: "减速跟随"
这样做的好处是什么?测试工程师改数据就行,不用碰代码。我在项目里遇到过测试同学不敢改脚本的情况,用了数据驱动之后,他们自己就能加测试场景了。
基础设施层
这一层最容易被忽视,但也最重要。它包括:
- 硬件接口封装(CAN、以太网、串口)
- 日志记录和报告生成
- 测试环境管理(仿真器、实车、HIL)
- 公共工具函数(时间戳、数据解析、断言库)
注意:基础设施层不要依赖任何业务逻辑。它应该是「万金油」,换一个项目也能直接用。我曾经因为把业务判断写进了底层驱动,导致换了个传感器型号,底层代码重写了三遍。血的教训。
模块化与可扩展性
模块化设计,说白了就是「高内聚、低耦合」。每个模块只做一件事,并且做好。
我常用的做法是:
- 按ADAS功能划分模块:ACC、LKA、AEB、BSD各一个包
- 每个模块内部再分:操作类、校验类、数据类
- 模块之间通过接口通信,不直接调用内部方法
举个例子,如果你要新增一个「交通标志识别」的测试模块,只需要:
- 新建
tsr/目录 - 实现
TSROperation和TSRCheck类 - 在数据层添加TSR的测试数据
- 写用例调用即可
完全不需要改已有的ACC或LKA模块。这就是可扩展性。
数据驱动与关键字驱动
这两个概念经常被混在一起说,其实它们各有侧重。
| 驱动方式 | 核心思想 | 适用场景 |
|---|---|---|
| 数据驱动 | 用数据控制测试流程 | 参数多、组合多的场景 |
| 关键字驱动 | 用关键字描述测试步骤 | 非技术人员编写用例 |
我个人更推荐数据驱动。为什么?因为ADAS测试的数据组合实在太多了。车速、距离、光照、天气、道路曲率...你想想看,光一个AEB就有上百种参数组合。用数据驱动,一个测试脚本能跑几百条用例。
关键字驱动呢?它更适合让产品经理或测试工程师用自然语言写用例。比如:
关键字: 激活ACC
参数: 车速=120km/h, 跟车距离=3档
步骤:
1. 按下方向盘ACC按钮
2. 设定目标车速
3. 确认ACC图标亮起
两种方式不冲突。我见过最好的实践是:底层用数据驱动保证效率,上层用关键字驱动降低门槛。
持续集成(CI)集成
自动化测试如果不跑在CI上,那跟没写差不多。你想想看,手动触发测试、等结果、看报告...这一套下来半天就没了。
我建议的CI集成方案:
- 提交触发:每次代码合并到main分支,自动跑全量回归
- 定时触发:每天凌晨跑一次全量测试,早上看报告
- 条件触发:特定文件变更时,只跑相关模块的测试
一个实用的CI流水线示例(Jenkinsfile):
pipeline {
agent any
stages {
stage('环境准备') {
steps {
sh 'python -m venv venv'
sh 'source venv/bin/activate && pip install -r requirements.txt'
}
}
stage('单元测试') {
steps {
sh 'pytest tests/unit/ --junitxml=report_unit.xml'
}
}
stage('集成测试') {
steps {
sh 'pytest tests/integration/ --junitxml=report_integ.xml'
}
}
stage('生成报告') {
steps {
sh 'python scripts/generate_report.py'
}
}
}
post {
always {
junit 'report_*.xml'
archiveArtifacts artifacts: 'report/*.html'
}
}
}
避坑指南:我曾经把全量回归放在每次提交都跑,结果CI排队排到天荒地老。后来改成「提交跑冒烟测试,定时跑全量回归」,效率提升了好几倍。记住,CI不是越频繁越好,而是越精准越好。
好了,这一章的内容就这些。框架设计这件事,说起来简单,做起来全是细节。下一章我会讲具体的框架搭建实战,到时候咱们手把手写代码。
本章要点回顾:
- 四层架构:用例层 → 业务逻辑层 → 数据驱动层 → 基础设施层
- 模块化:按功能划分,接口通信,互不依赖
- 数据驱动优先,关键字驱动辅助
- CI集成要分层级:冒烟测试快跑,全量测试定时跑