第4章:测试环境搭建——Simulink/Stateflow测试环境配置、测试脚本与自动化框架介绍

好,咱们进入实战环节了。前面聊了那么多MIL的概念和流程,这一章咱们得把袖子撸起来,真正把测试环境搭起来。说实话,很多新手工程师在模型上花的时间不少,但一到搭测试环境就头疼。我当年刚入行时也踩过不少坑,今天就把这些经验掰开揉碎讲给你听。

4.1 Simulink/Stateflow测试环境配置

先说说Simulink测试环境。你想想看,一个复杂的控制模型,动辄几十个模块,几百个信号。如果没有一个规范的测试环境,那调试起来简直是一场噩梦。

我个人习惯是把测试环境分成三层:

  • 测试平台层:负责信号注入、数据采集、结果比对
  • 被测模型层:就是咱们的Simulink/Stateflow模型
  • 测试用例层:存放各种测试场景和参数

这三层之间用接口模块连接,互不干扰。我在项目中遇到过好几次,因为测试环境和模型混在一起,最后改模型时把测试脚本也搞乱了。所以,一定要分开

4.1.1 基础配置步骤

  1. 创建测试工程目录:建议用Git管理,目录结构要清晰。比如:test/model/script/data/
  2. 配置求解器:固定步长,离散求解器。我一般用ode1ode3,步长根据模型需求定,通常是0.01s或0.001s
  3. 设置信号记录:把关键信号都打上log标记,方便后续分析
  4. 配置Stateflow:注意设置Enable debugging/animation,调试时很有用

重要提醒:Stateflow的初始化状态一定要明确。我曾经有个项目,因为Stateflow的默认状态没设对,导致仿真一开始就跑飞了。排查了两天才找到原因,教训深刻。

4.1.2 测试信号注入方式

测试信号怎么注入?说白了就三种方式:

方式 适用场景 优缺点
手动输入 快速验证、调试 灵活但不可重复
From Workspace 批量测试、回归测试 可重复,但需要提前准备数据
Signal Builder 复杂波形测试 可视化,但脚本化困难

我个人更推荐From Workspace方式。为什么呢?因为你可以用MATLAB脚本生成各种测试数据,然后一键注入。这在自动化测试中特别有用。

4.2 测试脚本编写

好,环境搭好了,接下来就是写测试脚本。很多新手觉得写脚本麻烦,其实不然。一个规范的测试脚本,能帮你节省80%的重复劳动。

4.2.1 基础测试脚本模板

我给大家一个我常用的脚本模板:

%% 测试脚本模板 - 第4章示例
% 作者:资深工程师
% 功能:MIL测试基础脚本

% 1. 清空环境
clear; clc; close all;

% 2. 加载模型
modelName = 'myController';
load_system(modelName);

% 3. 设置测试参数
testParam.stepTime = 0.01;
testParam.simTime = 10;
testParam.inputSignal = [0, 1, 0, -1, 0];  % 方波信号

% 4. 注入测试信号
assignin('base', 'testInput', testParam.inputSignal);

% 5. 运行仿真
simOut = sim(modelName, 'SimulationMode', 'normal', ...
             'StopTime', num2str(testParam.simTime));

% 6. 提取结果
outputData = simOut.get('outputSignal');
timeData = simOut.get('tout');

% 7. 结果比对
expectedOutput = [0, 0.5, 0, -0.5, 0];  % 期望输出
if max(abs(outputData - expectedOutput)) < 0.01
    disp('测试通过!');
else
    disp('测试失败!');
end

% 8. 清理
close_system(modelName, 0);

小技巧:脚本里一定要加try-catch结构。我曾经有一次跑批量测试,中间一个用例报错,整个脚本就停了。加了异常处理之后,即使某个用例失败,也能继续跑后面的。

4.2.2 测试脚本的模块化设计

你想想看,如果每个测试用例都写一个完整的脚本,那维护起来得多累?所以,我建议把脚本拆成几个函数:

  • setupTest.m:初始化环境,加载模型
  • runTestCase.m:执行单个测试用例
  • checkResult.m:比对结果,生成报告
  • teardownTest.m:清理环境

这样做的好处是,你只需要写一次基础框架,后面加新用例时,只需要修改参数文件就行了。

4.3 自动化测试框架介绍

说到自动化测试框架,很多公司都有自己的方案。但万变不离其宗,核心就三个字:可重复可追溯可报告

4.3.1 轻量级框架:基于MATLAB脚本

对于小团队或者项目初期,我推荐用MATLAB自带的sltest工具箱。它提供了:

  • sltest.testmanager:管理测试用例
  • sltest.testsequence:定义测试序列
  • sltest.testharness:自动生成测试平台

举个例子,用sltest.testmanager创建一个测试套件:

%% 创建测试管理器
tf = sltest.testmanager.TestFile('myTestFile.mldatx');
ts = tf.createTestSuite('ControllerTestSuite');

% 添加测试用例
tc1 = ts.createTestCase('TestCase1');
tc1.setModel('myController');
tc1.setSimulationMode('Normal');
tc1.setStopTime('10');

% 设置信号
tc1.addSignal('inputSignal', 'FromWorkspace', 'testInput');
tc1.addSignal('outputSignal', 'Logging', 'on');

% 运行测试
resultObj = tf.run();
resultObj.displayResults();

注意sltest工具箱需要额外的License。如果公司没买,可以用纯脚本实现。我早期在一个小公司,就是纯手写的自动化框架,虽然简陋,但够用。

4.3.2 企业级框架:基于Python+MATLAB Engine

对于大型项目,我建议用Python做调度,MATLAB做仿真引擎。为什么?因为Python的生态更丰富,报告生成、数据可视化、CI/CD集成都更方便。

基本架构是这样的:

  1. Python调度层:读取测试用例(Excel/JSON),调用MATLAB Engine
  2. MATLAB执行层:运行Simulink仿真,返回结果
  3. Python报告层:生成HTML/PDF报告,上传到服务器

我在一个ADAS项目中就用过这个方案。当时有2000多个测试用例,纯MATLAB跑要3个小时。换成Python调度后,利用多进程并行跑,时间缩短到40分钟。效果非常明显。

4.3.3 自动化框架的核心要素

不管用什么工具,一个成熟的自动化框架应该包含:

要素 说明 我的建议
用例管理 支持增删改查,版本控制 用Excel管理,简单直观
执行引擎 支持批量、并行、定时执行 优先考虑并行能力
结果比对 支持数值、波形、时序比对 设定合理的容差范围
报告生成 自动生成测试报告 包含通过率、覆盖率、失败原因
需求追溯 每个用例关联需求ID 这是MIL测试的灵魂

4.4 实战避坑指南

最后,分享几个我踩过的坑:

坑1:仿真时间设置不当

我曾经有一个项目,模型里有个积分环节,仿真时间设得太短,积分还没稳定就结束了。结果测试一直失败,后来发现是仿真时间不够。建议:先跑一个长仿真,观察信号稳定时间,再确定合适的仿真时长。

坑2:信号别名冲突

Simulink里信号名字如果重复,会导致数据记录混乱。我建议在模型里给每个信号加前缀,比如IN_OUT_INT_,一眼就能看出信号类型。

坑3:忽略Stateflow的时序

Stateflow的状态切换是有时序的。如果你在同一个时间步里既改变输入又检查输出,可能会得到错误结果。建议:输入信号提前一个时间步注入,或者用delay模块做同步。

嗯,这一章的内容就到这里。测试环境搭建看似基础,但基础不牢,地动山摇。下一章我们会讲测试用例的设计方法,到时候会用到今天搭的环境。记得把代码跑一遍,有问题随时交流。