从需求到认证的完整流程
📋 前言
在当今复杂的嵌入式系统开发中,模型测试已成为确保产品质量和安全性的关键环节。特别是在汽车、轨道交通等安全关键领域,系统化的模型测试不仅是技术要求,更是法规合规的必要条件。
本文将为您详细介绍模型测试的核心概念、方法和最佳实践,帮助您建立一套完整的测试体系。
备注:团队的学习笔记分享,如果需要相关模型测试的工具请联系我们(support@softor.com.cn)文章中如果写的有错误,请批评指正。
🎯 为什么需要模型测试?
1️⃣ 验证模型正确性
- • 确保模型训练过程没有错误
- • 验证模型推理结果符合预期
- • 检查模型是否收敛到合理状态
2️⃣ 评估模型性能
- • 准确率、精确率、召回率等指标
- • 推理速度和资源占用
- • 在不同数据集上的表现
3️⃣ 保证模型稳定性
- • 检测过拟合和欠拟合
- • 验证模型在不同输入下的鲁棒性
- • 确保模型在生产环境中稳定运行
4️⃣ 满足功能安全标准
在高安全要求的行业,模型测试是满足功能安全标准的必要条件:
- • 证明模型符合安全需求
- • 提供测试证据和文档
- • 达到规定的安全完整性等级
🔒 功能安全标准认证
主要认证标准
| 标准 | 适用领域 | 说明 |
|---|---|---|
| IEC 61508 | 工业自动化 | 功能安全通用标准 |
| EN 50128 | 轨道交通 | 铁路应用软件开发标准 |
| ISO 25119 | 农业机械 | 农业和林业机械安全标准 |
| IEC 62304 | 医疗设备 | 医疗器械软件生命周期标准 |
| ISO 26262 | 汽车电子 | 道路车辆功能安全标准(最新版支持最高工具置信度水平 TCL 3,可达到最高安全级别 ASIL D) |
| ASPICE | 汽车软件 | 汽车软件过程改进和能力评定 |
为什么需要标准认证?
- • 法规合规 – 满足行业准入要求
- • 质量保证 – 确保测试工具本身的可靠性
- • 责任界定 – 明确工具供应商和使用方的责任
- • 互认互通 – 国际项目中的通用认可
📝 测试内容详解
1. 基于需求的测试
模型和代码的功能测试
什么是基于需求的测试?
基于需求的测试就是根据产品的功能需求来设计测试用例,确保模型和代码能够正确实现所有要求的功能。简单来说,就是”按要求测试”,确保系统做了它应该做的事情。
测试内容:
- • 根据需求规格说明书设计测试用例
- • 验证模型实现是否符合需求
- • 确保每个需求都有对应的测试覆盖
测试方法:
- 1. 需求分析:仔细阅读需求文档,提取出所有需要测试的功能点
- 2. 测试用例设计:为每个功能点设计具体的测试场景
- 3. 测试执行:运行测试用例并记录结果
- 4. 结果验证:检查实际输出是否与预期结果一致
实际例子:自适应巡航控制系统(ACC)
业务场景:在高速公路上,ACC系统需要根据前方车辆的速度自动调整本车速度,以保持安全距离。
需求:当前方车辆减速时,ACC系统应自动减速以保持安全距离(安全距离 = 速度 × 0.3秒)
测试用例:
- 1. 正常跟随场景:前方车辆以100km/h行驶,测试车辆以100km/h跟随,验证安全距离保持在约8.3米(100km/h × 0.3秒)
- 2. 前方车辆减速场景:前方车辆从100km/h突然减速至60km/h,验证测试车辆是否也自动减速至60km/h,并保持约5米的安全距离
- 3. 前方车辆停止场景:前方车辆完全停止,验证测试车辆是否安全停止,且与前方车辆保持约2米的停车距离
- 4. 前方车辆加速场景:前方车辆从60km/h加速至100km/h,验证测试车辆是否平稳加速跟随
代码示例(简化的ACC控制逻辑):
void acc_control(float target_speed, float front_vehicle_speed, float distance)
{
float safe_distance = target_speed * 0.3; // 安全距离计算公式
if (distance < safe_distance) {
// 距离过近,需要减速
if (front_vehicle_speed < target_speed) {
set_vehicle_speed(front_vehicle_speed);
} else {
set_vehicle_speed(target_speed);
}
} else {
// 距离合适,保持目标速度
set_vehicle_speed(target_speed);
}
}
测试覆盖:确保减速、加速、停止等所有功能需求都被完全测试覆盖
2. 测试执行阶段(MiL/SiL/PiL/HiL)
什么是虚拟集成测试?
虚拟集成测试(Virtual Integration Testing)是指在虚拟环境中对嵌入式系统进行测试的方法,通过模拟真实环境来验证系统的功能和性能。它不需要实际的硬件,可以在开发早期就进行测试,大大降低了测试成本和风险。
虚拟集成测试的四个阶段
在嵌入式软件测试中,根据测试执行环境的不同,分为以下四个阶段:
| 测试阶段 | 英文全称 | 说明 | 特点 | 测试环境 |
|---|---|---|---|---|
| MiL | Model-in-the-Loop | 模型在环测试 | 在模型层面进行仿真测试,验证模型逻辑正确性 | Simulink/Stateflow等建模环境 |
| SiL | Software-in-the-Loop | 软件在环测试 | 在宿主机上运行生成的代码,验证代码功能 | PC/工作站(Windows/Linux) |
| PiL | Processor-in-the-Loop | 处理器在环测试 | 在目标处理器上运行代码,验证处理器兼容性 | 目标ECU或仿真器 |
| HiL | Hardware-in-the-Loop | 硬件在环测试 | 在实际硬件环境中测试,验证系统集成 | 实际ECU + 传感器/执行器 |
各阶段详细说明
1. MiL(Model-in-the-Loop)- 模型在环测试
- • 定义:在建模环境中直接对控制算法模型进行测试
- • 测试对象:控制算法模型(如Simulink模型)
- • 测试环境:PC上的建模软件(Simulink、Stateflow等)
- • 测试目的:
- • 验证控制算法逻辑的正确性
- • 检查模型设计的合理性
- • 早期发现设计缺陷
- • 优势:
- • 测试速度快,修改方便
- • 不需要实际硬件
- • 可以快速迭代
- • 实际例子:
% 在Simulink中测试ACC控制模型
sim('acc_control_model.slx');
% 分析仿真结果,验证控制逻辑
2. SiL(Software-in-the-Loop)- 软件在环测试
- • 定义:在宿主机上运行自动生成的代码进行测试
- • 测试对象:从模型自动生成的C/C++代码
- • 测试环境:PC或工作站(Windows/Linux)
- • 测试目的:
- • 验证代码生成的正确性
- • 检查代码功能是否与模型一致
- • 进行初步的性能测试
- • 优势:
- • 不需要目标硬件
- • 可以使用丰富的调试工具
- • 测试成本较低
- • 实际例子:
// 在PC上编译并运行生成的C代码
#include "acc_control.h"
int main() {
acc_control_init();
acc_control_run(100.0, 80.0, 10.0); // 测试ACC控制
return 0;
}
3. PiL(Processor-in-the-Loop)- 处理器在环测试
- • 定义:在目标处理器或仿真器上运行代码进行测试
- • 测试对象:编译后的目标代码
- • 测试环境:目标ECU、处理器仿真器或开发板
- • 测试目的:
- • 验证代码在目标处理器上的正确性
- • 检查处理器兼容性
- • 测试实时性能
- • 优势:
- • 接近真实运行环境
- • 可以测试处理器特定的行为
- • 验证实时性要求
- • 实际例子:
// 在目标ECU上运行代码
// 通过串口或CAN总线与PC通信
void main() {
acc_control_init();
while(1) {
float speed = read_speed_sensor();
float target_speed = read_target_speed();
acc_control_run(speed, target_speed, 0.0);
}
}
4. HiL(Hardware-in-the-Loop)- 硬件在环测试
- • 定义:在实际硬件环境中对ECU进行测试
- • 测试对象:完整的ECU系统
- • 测试环境:HiL测试台架(包含ECU、传感器、执行器等)
- • 测试目的:
- • 验证系统集成
- • 测试与外部设备的交互
- • 模拟各种故障场景
- • 优势:
- • 最接近真实运行环境
- • 可以测试完整的系统行为
- • 可以模拟各种边界和故障情况
- • 实际例子:
// 在HiL台架上测试
// HiL系统模拟车辆动力学、传感器信号等
// ECU接收模拟信号,输出控制信号
// 测试各种驾驶场景和故障情况
虚拟集成测试的优势
- 1. 早期发现问题:在开发早期就能进行测试,降低后期修复成本
- 2. 降低测试成本:不需要大量实际硬件,减少测试设备投入
- 3. 提高测试效率:自动化程度高,可以快速执行大量测试用例
- 4. 增强测试覆盖率:可以模拟各种边界和异常情况
- 5. 支持持续集成:可以集成到CI/CD流程中,实现自动化测试
测试流程:
需求分析 → 模型设计 → MiL测试 → 代码生成 → SiL测试 → PiL测试 → HiL测试 → 实车测试
实际应用场景
汽车电子领域:
- • 发动机控制系统测试
- • 制动系统测试(ABS、ESP)
- • 自适应巡航控制(ACC)测试
- • 车身控制模块测试
工业自动化领域:
- • PLC控制系统测试
- • 机器人控制系统测试
- • 过程控制系统测试
航空航天领域:
- • 飞行控制系统测试
- • 航空电子系统测试
- • 导航系统测试
3. 背靠背测试
全自动等效性测试
什么是背靠背测试?
背靠背测试就像是让两个学生做同一份试卷,然后对比他们的答案是否一致。在模型测试中,就是让模型和生成的代码执行相同的测试用例,然后对比它们的输出结果,确保代码生成过程没有引入错误。
测试内容:
- • 对比模型在不同环境(如Simulink vs 生成代码)下的输出
- • 验证代码生成过程没有引入错误
- • 自动化执行,提高效率
测试方法:
- 1. 基准测试:在原始模型环境(如Simulink)中运行测试用例,获取基准输出(MiL)
- 2. 代码测试:在目标环境(如生成的C代码)中运行相同测试用例(SiL/PiL)
- 3. 结果对比:自动对比两组输出结果
- 4. 差异分析:标记差异并生成测试报告
实际例子:发动机燃油喷射控制
业务场景:发动机控制系统需要根据转速、负载等参数精确计算燃油喷射量,以确保发动机高效运行。
模型与代码:
- • 模型:在Simulink中设计的发动机燃油喷射控制算法模型
- • 代码:通过代码生成工具从模型自动生成的C代码
测试用例:
| 测试场景 | 转速(rpm) | 负载(%) | 预期燃油喷射量(ms) |
|---|---|---|---|
| 怠速工况 | 800 | 10 | 2.5 |
| 部分负荷 | 2000 | 50 | 4.8 |
| 全负荷 | 4000 | 100 | 8.2 |
| 急加速 | 3000→4500 | 80→100 | 6.5→9.0 |
测试过程:
- 1. MiL测试:在Simulink中运行上述测试用例,记录模型的燃油喷射量输出作为基准
- 2. SiL测试:在宿主机上运行生成的C代码,使用相同的测试用例
- 3. PiL测试:在目标ECU处理器上运行代码,使用相同的测试用例
- 4. 结果对比:自动对比三种环境下的输出结果
- 5. 差异分析:如果结果不一致,分析原因并修复
代码示例(自动生成的燃油喷射控制代码):
float calculate_fuel_injection(float rpm, float load)
{
// 基于转速和负载的燃油喷射量计算
float base_injection = 0.001 * rpm + 0.05 * load;
float correction = 0.0;
// 温度修正
if (engine_temp < 60.0) {
correction = 0.5;
}
return base_injection + correction;
}
4. 覆盖率分析
代码及模型覆盖率统计(死代码检测)
什么是覆盖率分析?
覆盖率分析就像是检查我们的测试用例是否覆盖了所有的代码路径,确保没有遗漏任何重要的功能。它可以帮助我们发现哪些代码没有被测试到,哪些代码可能是多余的(死代码)。
测试内容:
- • 语句覆盖:确保每一行代码都被执行过
- • 分支覆盖:确保每个条件分支(如if-else)都被测试过
- • MC/DC覆盖:确保每个条件的变化都能独立影响决策结果
- • 死代码检测:识别永远不会被执行的代码
- • 测试充分性:确保测试用例足够全面
- • 圈复杂度分析:评估代码复杂度和可测试性
测试方法:
- 1. 数据收集:在测试执行过程中收集覆盖率数据
- 2. 报告生成:生成详细的覆盖率报告
- 3. 路径分析:分析未覆盖的代码路径
- 4. 用例补充:针对未覆盖的路径补充测试用例
- 5. 死代码处理:识别并处理死代码
- 6. 圈复杂度计算:使用McCabe方法计算圈复杂度
覆盖率标准:
| 覆盖类型 | 要求 | 适用场景 |
|---|---|---|
| 语句覆盖 | 100% | 基础要求 |
| 分支覆盖 | 100% | 安全关键功能 |
| MC/DC覆盖 | 100% | 最高安全等级(ASIL D) |
圈复杂度(Cyclomatic Complexity)
什么是圈复杂度?
圈复杂度(Cyclomatic Complexity)是由Thomas McCabe提出的一种软件度量指标,用于评估代码的复杂度和可测试性。它反映了程序中独立路径的数量。
计算公式:
圈复杂度 = E - N + 2P
其中:
- • E:图中边的数量
- • N:图中节点的数量
- • P:连通分量的数量
简化计算方法:
圈复杂度 = 判定节点数量 + 1
判定节点包括:if语句、while循环、for循环、case语句等。
圈复杂度标准:
| 圈复杂度 | 代码质量 | 建议 |
|---|---|---|
| 1-10 | 低风险 | 代码简单,易于测试和维护 |
| 11-20 | 中等风险 | 代码复杂度适中,需要关注 |
| 21-50 | 高风险 | 代码复杂,建议重构 |
| >50 | 极高风险 | 代码过于复杂,必须重构 |
实际例子:
// 圈复杂度 = 4(3个if + 1)
void abs_control(float speed, float brake_pressure, float wheel_speed)
{
float slip_ratio = (speed - wheel_speed) / speed;
if (speed > 100 && brake_pressure > 50 && slip_ratio > 0.2) { // 判定1
apply_abs_pulse();
} else if (speed > 50 && slip_ratio > 0.15) { // 判定2
apply_abs_regular();
} else if (brake_pressure > 70) { // 判定3
apply_regular_brake();
} else {
apply_light_brake();
}
}
圈复杂度在测试中的作用:
- 1. 测试用例数量:圈复杂度表示至少需要多少个测试用例才能覆盖所有可能的执行路径
- 2. 代码质量评估:高圈复杂度通常意味着代码难以理解和维护
- 3. 重构指导:当圈复杂度过高时,建议将函数拆分为多个小函数
- 4. 安全标准要求:ISO 26262等安全标准对圈复杂度有明确要求
降低圈复杂度的方法:
- 1. 函数拆分:将复杂函数拆分为多个小函数
- 2. 使用策略模式:用多态替代复杂的条件判断
- 3. 卫语句:尽早返回,减少嵌套层级
- 4. 状态机:用状态机管理复杂的状态转换
降低圈复杂度示例:
// 原始代码:圈复杂度 = 5
void process_order(Order* order) {
if (order != NULL) {
if (order->status == PENDING) {
if (order->amount > 1000) {
if (order->customer->vip_level > 2) {
apply_discount(order, 0.2);
} else {
apply_discount(order, 0.1);
}
} else {
process_normal(order);
}
} else {
reject_order(order);
}
}
}
// 重构后:圈复杂度 = 2
void process_order(Order* order) {
if (order == NULL) return;
if (order->status != PENDING) {
reject_order(order);
return;
}
if (order->amount > 1000) {
apply_vip_discount(order);
} else {
process_normal(order);
}
}
void apply_vip_discount(Order* order) {
if (order->customer->vip_level > 2) {
apply_discount(order, 0.2);
} else {
apply_discount(order, 0.1);
}
}
实际例子:防抱死制动系统(ABS)控制
业务场景:ABS系统需要根据车速和制动压力自动调整制动模式,以防止车轮抱死。
代码示例:
void abs_control(float speed, float brake_pressure, float wheel_speed)
{
// 计算滑移率
float slip_ratio = (speed - wheel_speed) / speed;
if (speed > 100 && brake_pressure > 50 && slip_ratio > 0.2) {
// 高速高压力下的ABS控制
apply_abs_pulse();
} else if (speed > 50 && slip_ratio > 0.15) {
// 中速下的ABS控制
apply_abs_regular();
} else if (brake_pressure > 70) {
// 高压力下的常规制动
apply_regular_brake();
} else {
// 低速或低压力下的轻度制动
apply_light_brake();
}
}
覆盖率测试:
1. 语句覆盖测试用例:
- • 测试用例1:speed=120, brake_pressure=60, slip_ratio=0.25 → 进入第一个分支
- • 测试用例2:speed=60, brake_pressure=40, slip_ratio=0.18 → 进入第二个分支
- • 测试用例3:speed=40, brake_pressure=80, slip_ratio=0.1 → 进入第三个分支
- • 测试用例4:speed=30, brake_pressure=30, slip_ratio=0.05 → 进入第四个分支
2. 分支覆盖测试用例:
- • 测试所有条件的真假组合,确保每个分支都被测试到
3. MC/DC覆盖测试用例:
- • 确保每个条件独立影响决策结果
- • 例如:测试speed > 100对结果的独立影响,保持其他条件不变
4. 死代码检测:
- • 分析是否存在永远不会执行的代码路径
- • 例如:如果speed <= 0时的处理逻辑
覆盖率报告示例:
| 覆盖类型 | 目标 | 实际 | 状态 |
|---|---|---|---|
| 语句覆盖 | 100% | 100% | ✅ |
| 分支覆盖 | 100% | 100% | ✅ |
| MC/DC覆盖 | 100% | 100% | ✅ |
| 死代码 | 0 | 0 | ✅ |
5. 形式化规格说明
需求形式化
什么是形式化规格说明?
形式化规格说明就是用数学语言来精确描述需求,消除自然语言的歧义,确保需求的准确性和一致性。简单来说,就是把模糊的文字描述变成精确的数学表达式。
测试内容:
- • 使用数学语言精确描述需求
- • 消除自然语言的歧义
- • 为形式化验证奠定基础
测试方法:
- 1. 需求转换:将自然语言需求转换为形式化描述
- 2. 规约定义:使用形式化语言(如Z语言、B方法)定义规约
- 3. 可追溯性:建立需求与实现之间的可追溯性
实际例子:安全气囊系统
业务场景:安全气囊系统需要在发生碰撞时,根据碰撞严重程度决定是否弹出气囊,以保护乘客安全。
自然语言需求:当汽车发生碰撞时,安全气囊应该在合适的时机弹出
形式化规格说明:
安全气囊弹出条件 = 碰撞加速度 > 30g 且 碰撞持续时间 > 10ms 且 车辆速度 > 20km/h
安全气囊不弹出条件 = 碰撞加速度 ≤ 30g 或 碰撞持续时间 ≤ 10ms 或 车辆速度 ≤ 20km/h
形式化语言表示(使用Z语言):
z
气囊弹出?: bool
气囊弹出? = (碰撞加速度 > 30) ∧ (碰撞持续时间 > 10) ∧ (车辆速度 > 20)
z
可追溯性:
- • 需求ID:REQ-001
- • 形式化规约ID:FSPEC-001
- • 实现模块:airbag_controller.c
通过形式化描述,我们消除了”合适的时机”这样的模糊表达,明确了安全气囊弹出的具体条件,为后续的验证奠定了基础。
6. 形式化验证
形式验证
什么是形式验证?
形式验证就是使用数学方法来证明系统的正确性,通过穷举所有可能的执行路径,确保系统在所有情况下都能正确运行。这是一种最高级别的验证方法,可以提供数学上的保证。
测试内容:
- • 通过数学证明验证系统正确性
- • 穷举所有可能的执行路径
- • 提供最高级别的正确性保证
测试方法:
- 1. 模型建立:建立系统的形式化模型
- 2. 属性定义:定义需要验证的属性(如安全性、活性)
- 3. 验证执行:使用模型检测或定理证明工具进行验证
- 4. 结果分析:分析验证结果并修复问题
实际例子:火车信号控制系统
业务场景:火车信号系统需要控制不同火车在轨道网络中的运行,确保不会发生碰撞。
系统需求:确保在任何情况下,同一轨道上不会有两列火车同时行驶
形式化模型:
- • 状态变量:火车位置、轨道占用状态、信号状态
- • 转换关系:火车移动规则、信号控制逻辑
- • 安全属性:对于任何时刻t,任何轨道segment s,最多只有一列火车在s上
形式验证过程:
- 1. 模型建立:使用模型检测工具(如NuSMV)建立火车信号系统的形式化模型
- 2. 属性定义:定义安全属性公式
AG (∀s ∈ 轨道, ∀t1,t2 ∈ 火车, t1 ≠ t2 → ¬(在轨道s上(t1) ∧ 在轨道s上(t2))) - 3. 验证执行:使用模型检测工具验证安全属性
- 4. 结果分析:
- • 如果验证通过:系统设计正确,不存在碰撞风险
- • 如果验证失败:工具会生成反例,显示导致碰撞的具体场景
代码示例(信号控制逻辑):
bool is_track_free(int track_id)
{
for (int i = 0; i < MAX_TRAINS; i++) {
if (trains[i].current_track == track_id && trains[i].status == RUNNING) {
return false;
}
}
return true;
}
void control_signal(int track_id, int signal_id)
{
if (is_track_free(track_id)) {
set_signal_green(signal_id);
} else {
set_signal_red(signal_id);
}
}
验证结果:
- • 成功案例:验证通过,证明系统在所有场景下都能防止碰撞
- • 失败案例:发现当两列火车同时接近同一轨道时,信号可能出现竞争条件,导致两列火车同时进入轨道
通过形式验证,我们可以确保火车信号系统的安全性,避免碰撞事故的发生。
📋 七、测试流程
7.1 测试流程概述
模型开发的测试流程包括以下7个关键阶段:
- 1. 需求分析
- • 理解功能需求和安全需求
- • 识别测试需求
- • 确定测试范围和目标
- 2. 测试设计
- • 设计测试用例(基于需求)
- • 确定测试覆盖目标(语句覆盖、分支覆盖、MC/DC覆盖)
- • 准备测试数据和测试环境
- 3. 功能测试
- • 执行Requirements-based Testing
- • 验证模型功能正确性
- • 检查是否满足所有需求
- 4. 等效性测试
- • 执行Back-to-Back Test
- • 对比模型与代码输出
- • 确保代码生成的正确性
- 5. 覆盖率分析
- • 执行Coverage Analysis
- • 统计代码/模型覆盖率
- • 识别死代码和未覆盖的部分
- 6. 形式化验证(高安全等级要求)
- • 执行Formal Specification
- • 执行Formal Verification
- • 确保系统安全性和可靠性
- 7. 测试报告与认证
- • 生成测试报告
- • 准备认证文档
- • 确保符合安全标准要求
7.2 测试流程图示
需求分析 → 测试设计 → 功能测试 → 等效性测试 → 覆盖率分析 → 形式化验证 → 测试报告与认证
🔄 八、开发工作流程与测试方法映射
8.1 开发与测试关系
| 开发阶段 | 对应测试方法 | 测试目标 |
|---|---|---|
| 需求分析 | Requirements-based Testing | 确保测试覆盖所有需求 |
| 模型设计 | 功能测试、形式化规格说明 | 验证模型功能正确性 |
| 代码生成 | Back-to-Back Test | 确保代码与模型行为一致 |
| 集成测试 | 覆盖率分析 | 确保代码被充分测试 |
| 系统测试 | 形式化验证 | 确保系统安全性 |
8.2 测试执行环境映射
| 测试方法 | 执行环境 | 适用阶段 |
|---|---|---|
| 功能测试 | MiL (Model-in-the-Loop) | 模型设计阶段 |
| 等效性测试 | MiL → SiL → PiL | 代码生成阶段 |
| 覆盖率分析 | SiL, PiL | 集成测试阶段 |
| 形式化验证 | 模型级、代码级 | 全生命周期 |
| 系统验证 | HiL (Hardware-in-the-Loop) | 系统测试阶段 |
8.3 测试方法应用场景
- • Requirements-based Testing:适用于所有安全等级的功能验证
- • Back-to-Back Test:适用于代码生成后的一致性验证
- • Coverage Analysis:适用于ASIL B及以上安全等级的代码测试
- • Formal Verification:适用于ASIL D安全等级的关键功能验证
💡 九、最佳实践
9.1 测试数据准备
- • 使用与训练数据分布一致的测试集
- • 准备边缘案例和异常数据
- • 确保测试数据的代表性和多样性
9.2 测试指标选择
- • 根据业务场景选择合适的评估指标
- • 不仅关注单一指标,要综合评估
- • 设置合理的性能阈值
9.3 自动化测试
- • 将模型测试集成到CI/CD流程
- • 定期运行回归测试
- • 建立测试报告和告警机制
9.4 持续监控
- • 上线后持续监控模型表现
- • 建立数据漂移检测
- • 及时发现模型退化问题
�� ISO 26262-6 软件单元测试方法
根据ISO 26262-6标准,软件单元测试需要采用以下方法:
软件单元测试方法(Table 10)
| 方法 | ASIL A | ASIL B | ASIL C | ASIL D | 说明 |
|---|---|---|---|---|---|
| 1a 基于需求的测试 | ++ | ++ | ++ | ++ | 根据需求规格设计测试用例 |
| 1b 接口测试 | ++ | ++ | ++ | ++ | 验证模块间接口正确性 |
| 1c 故障注入测试 | + | + | + | ++ | 通过注入故障验证容错能力 |
| 1d 资源使用测试 | + | + | + | ++ | 验证内存、CPU等资源使用 |
| 1e 背靠背对比测试 | + | + | ++ | ++ | 对比模型与代码输出一致性 |
测试用例设计方法(Table 11)
| 方法 | ASIL A | ASIL B | ASIL C | ASIL D | 说明 |
|---|---|---|---|---|---|
| 1a 需求分析 | ++ | ++ | ++ | ++ | 分析需求以确定测试范围 |
| 1b 等价类生成与分析 | + | ++ | ++ | ++ | 将输入划分为等价类进行测试 |
| 1c 边界值分析 | + | ++ | ++ | ++ | 测试边界条件下的系统行为 |
| 1d 错误推测 | + | + | + | + | 基于经验推测可能的错误 |
符号说明:
- •
++强烈推荐- •
+推荐
🔧 测试套件功能
1. 功能测试套件
就像是一个测试管理员
主要功能:
- • 测试用例管理:手工创建或管理测试用例,就像创建和整理考试题目一样
- • 需求链接:导入需求(如来自DOORS、Excel等)并自动链接到测试用例,实现双向可追溯,就像给每个测试题目标注对应的知识点
- • 多环境测试:可对任意层级的子系统自动进行MiL/SiL/PiL测试,就像在不同的考试环境中测试学生的表现
- • 结果比对:自动和预期结果进行比照,就像自动批改试卷并标记错误
- • 覆盖率分析:针对需求、模型、C代码,测试并生成覆盖率报告,就像分析学生在各个知识点上的掌握情况
- • 调试环境:自动生成调试环境,就像为学生提供专门的学习辅导环境
实际例子:
假设我们开发一个汽车空调控制系统:
- • 从Excel导入需求:”当温度设置为25℃时,系统应将车内温度控制在23-27℃之间”
- • 功能测试套件自动创建测试用例,在MiL、SiL、PiL环境中测试
- • 自动比对实际温度与预期范围
- • 生成覆盖率报告,确保所有温度控制逻辑都被测试到
2. 背靠背测试套件
就像是一个严格的考官
主要功能:
- • 智能测试生成:自动生成满足C代码结构100%覆盖率的测试用例,就像自动生成一套全面的考试题目
- • 死代码检测:识别永远不会被执行的代码,就像发现课本中从未被使用的章节
- • 风险识别:识别计算溢出等风险,就像发现考试中可能出现的陷阱题
- • 自动比对:自动执行Back-to-Back测试,对比模型和代码的输出,就像让两个学生做同一份试卷并对比答案
- • 覆盖率目标:通过插件支持用户定义覆盖率目标(等价类、边界值等),并自动生成测试用例满足该目标,就像根据教学大纲自动生成针对性的练习题
- • 扩展功能:支持可扩展的功能(测试自动化、回归测试等),就像提供更多的学习工具和方法
实际例子:
开发一个发动机燃油喷射控制模型:
- • 背靠背测试套件自动生成测试用例,确保C代码的每个分支都被测试到
- • 检测到一段永远不会执行的死代码(如某个条件永远为假的if语句)
- • 发现一个可能导致计算溢出的变量定义
- • 自动对比模型和代码在不同转速下的燃油喷射量输出
- • 生成详细的对比报告,标记任何差异
3. 形式测试套件
就像是一个翻译官
主要功能:
- • 需求导入:导入自然语言需求(如来自DOORS、Excel等),就像接收一份用日常语言写的任务描述
- • 图形界面:提供直观的需求形式化图形界面,轻松进行需求形式化,就像使用可视化工具将日常语言翻译成数学公式
- • 多对象支持:被测对象支持Simulink模型、手写代码、dSPACE HiL系统等,就像能翻译不同类型的文档
- • 形式化编辑:提供直观的形式化编辑器,就像提供专业的翻译工具
实际例子:
处理一个汽车安全系统的需求:
- • 导入需求:”当车速超过120km/h时,系统应发出超速警告”
- • 使用形式测试套件的图形界面,将其转换为形式化描述:”如果 speed > 120 km/h,则 trigger_warning = true”
- • 保存这个形式化规约,为后续的形式验证做准备
4. 形式验证套件
就像是一个数学证明专家
主要功能:
- • 结果判定:自动判定仿真结果,就像自动检查数学证明的正确性
- • 测试生成:自动生成来自需求的测试用例,就像根据数学定理自动生成练习题
- • 调试支持:自动生成调试模型,就像为数学证明提供辅助工具
- • 形式测试:自动进行形式测试,生成报告,就像生成详细的数学证明过程
- • 模型检测:使用Model Checking技术数学穷举是否存在反例,就像通过穷举法验证数学定理的正确性
实际例子:
验证一个火车信号控制系统:
- • 形式验证套件根据需求自动生成测试用例
- • 使用Model Checking技术,穷举所有可能的火车运行场景
- • 验证是否存在两列火车同时进入同一轨道的情况
- • 生成详细的验证报告,证明系统的安全性
- • 如果发现问题,会提供具体的反例场景,帮助工程师修复
🚀 测试工具核心优势
提高效率
高质量测试确保按时交付优质产品:
- • 测试用例的设计解耦于测试技术与执行,易于维护
- • 一次构建,随时复用:测试设计元素可复用
- • 自动生成各个测试阶段的测试用例
- • 测试执行自动化
- • 通过将需求与测试用例关联,实现出色的可追溯性
一款工具,无限可能
一次测试部署,赋能全流程:
- • 涵盖整个开发周期:从单元测试到集成测试
- • 支持Matlab/Simulink、C/C++代码、以及来自各种不同测试供应商的测试工具与平台等
- • 支持从MiL、SiL、PiL到HiL的各种测试执行方法
- • 支持云上部署,适用CI流程
- • 非介入被测件,测试工作和项目时与被测件保持解耦
无缝集成
可以无缝集成到现有的工作流程和工具链中:
- • 与通用开发环境深度集成
- • 与所有CI环境和存储库兼容
- • 支持在Windows和Linux下执行测试
- • 能与各系统API顺畅通信
易用性
无需编程知识即可轻松应用于整个测试流程中:
- • 测试工程项目结构清晰
- • 测试用例和结果展示易于理解
- • 内置样例模板加速测试工作的开展
- • 测试执行过程稳定
- • 友好的用户体验
- • 一次测试架构搭建完成,即可复用测试用例和测试设计于其他项目,也可用于重构后的软件
🔄 测试流程
- 1. 需求分析 – 理解功能需求和安全需求,识别测试需求
- 2. 测试设计 – 设计测试用例(基于需求),确定测试覆盖目标,准备测试数据
- 3. 功能测试 – Requirements-based Testing,验证模型功能正确性
- 4. 等效性测试 – Back-to-Back Test,对比模型与代码输出
- 5. 覆盖率分析 – Coverage Analysis,统计代码/模型覆盖率,识别死代码
- 6. 形式化验证 – Formal Specification和Formal Verification(高安全等级要求)
- 7. 测试报告与认证 – 生成测试报告,准备认证文档
💡 最佳实践
测试数据准备
- • 使用与训练数据分布一致的测试集
- • 准备边缘案例和异常数据
- • 确保测试数据的代表性和多样性
测试指标选择
- • 根据业务场景选择合适的评估指标
- • 不仅关注单一指标,要综合评估
- • 设置合理的性能阈值
自动化测试
- • 将模型测试集成到CI/CD流程
- • 定期运行回归测试
- • 建立测试报告和告警机制
持续监控
- • 上线后持续监控模型表现
- • 建立数据漂移检测
- • 及时发现模型退化问题
🎉 总结
模型测试是确保模型质量和安全性的关键环节。通过遵循功能安全标准(如ISO 26262、IEC 61508等),采用系统化的测试方法(Requirements-based Testing、Back-to-Back Test、Coverage Analysis等),可以有效地:
- 1. 验证模型的正确性和可靠性
- 2. 满足行业安全标准要求
- 3. 降低系统风险
- 4. 提高产品质量
在高安全要求的领域,选择合适的测试工具类型并建立完善的测试流程,是项目成功的关键保障。
**如果需要进一步的帮助或有其他问题,请随时联系我们。
support@softor.com.cn
tianpengbo@softor.com.cn
**
希望对您的项目有所帮助!
