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各一个包
  • 每个模块内部再分:操作类、校验类、数据类
  • 模块之间通过接口通信,不直接调用内部方法

举个例子,如果你要新增一个「交通标志识别」的测试模块,只需要:

  1. 新建 tsr/ 目录
  2. 实现 TSROperationTSRCheck
  3. 在数据层添加TSR的测试数据
  4. 写用例调用即可

完全不需要改已有的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集成要分层级:冒烟测试快跑,全量测试定时跑