Simulink Test自动化(二)-基于脚本批量构建TestFile与TestSuite框架
1. 为什么需要批量构建TestFile与TestSuite做Simulink模型测试的朋友都知道当模型规模变大时手动创建测试文件简直是一场噩梦。我去年负责一个汽车电控单元项目模型包含200多个子系统每个子系统都需要单独测试。如果手动操作光是创建TestFile和TestSuite就得花上一整天还容易出错。脚本化批量创建的好处很明显效率提升原来需要几小时的工作现在几秒完成一致性保证所有测试文件结构统一避免人为差异可维护性强需求变更时只需修改脚本不用逐个文件调整举个实际例子我们团队最近接手一个变速箱控制项目模型包含15个功能模块每个模块需要3种测试场景。手动创建需要45次重复操作而用脚本只需要运行一次。2. 准备工作与环境配置2.1 基础环境检查在开始写脚本前确保你的环境已经就绪MATLAB版本建议R2020b及以上安装Simulink Test工具箱准备好待测试的Simulink模型文件可以用以下命令检查工具箱是否安装ver(sltest)2.2 模型结构分析好的脚本从清晰的模型分析开始。我通常会先用这个命令获取模型结构load_system(your_model.slx); blocks find_system(your_model,SearchDepth,1); disp(blocks);建议先绘制模型架构图明确需要测试的子系统列表各子系统的输入输出接口测试场景的分类方式3. 核心脚本编写实战3.1 创建TestFile的黄金法则创建TestFile是整个框架的基础这里有几个实用技巧% 清除已有测试文件 sltest.testmanager.clear; % 创建新TestFile testFile sltest.testmanager.TestFile(MyTestFile.mldatx); % 设置存储路径重要 testFile.FilePath fullfile(pwd,TestFiles);我强烈建议设置明确的文件存储路径否则文件可能散落在各处。曾经有个项目因为没设路径团队成员花了半天找测试文件。3.2 配置覆盖率选项的陷阱覆盖率设置看似简单但有几个坑我踩过covSettings getCoverageSettings(testFile); covSettings.RecordCoverage true; covSettings.MdlRefCoverage true; % 这些组合最实用 covSettings.MetricSettings dmc; % 决策条件MCDC covSettings.CoverageFiltering on; % 过滤库代码特别注意MetricSettings参数大小写敏感写成DMC会报错。建议先用getCoverageSettings检查当前配置。4. 构建TestSuite的最佳实践4.1 基础创建方法TestSuite相当于测试分类创建时要注意命名规范% 创建主TestSuite mainSuite createTestSuite(testFile,FunctionalTests); % 创建子分类三级结构更清晰 safetySuite createTestSuite(testFile,SafetyRequirements); performanceSuite createTestSuite(testFile,PerformanceTests);我习惯用功能域作为分类标准比如SafetyRequirementsFunctionalCorrectnessBoundaryCases4.2 处理默认TestSuite的坑新建TestFile时会自动生成一个New Test Suite 1建议删除defaultSuite getTestSuiteByName(testFile,New Test Suite 1); if ~isempty(defaultSuite) remove(defaultSuite); end曾经因为这个默认Suite没删除导致测试报告混乱排查了好久。5. 批量创建TestCase的技巧5.1 基础创建模式TestCase是真正的测试执行单元一个经典创建模式harnessList {Harness1,Harness2,Harness3}; % 假设已有harness列表 for i 1:length(harnessList) tc createTestCase(mainSuite,baseline,harnessList{i}); setProperty(tc,Model,your_model); setProperty(tc,HarnessOwner,your_model); setProperty(tc,HarnessName,harnessList{i}); end5.2 高级参数配置更专业的做法是配置迭代参数testCases {Nominal,MinValue,MaxValue}; for i 1:length(testCases) tc createTestCase(performanceSuite,equivalence,testCases{i}); setProperty(tc,Iterations,10); setProperty(tc,StopOnError,false); end6. 实战中的常见问题排查6.1 路径问题解决方案我遇到最多的报错是文件未找到解决方案% 确保路径正确 addpath(genpath(你的模型路径)); % 检查文件是否存在 if ~exist(your_model.slx,file) error(模型文件不存在); end6.2 句柄失效处理当脚本运行时间较长时可能出现句柄失效try testFile sltest.testmanager.TestFile(MyTestFile.mldatx); catch ME disp(句柄失效重新创建...); sltest.testmanager.clear; testFile sltest.testmanager.TestFile(MyTestFile.mldatx); end7. 完整脚本示例与解析下面是我在一个真实项目中使用的脚本框架%% 初始化 clear; clc; modelName EngineControlSystem; testCategories {FuelInjection,Ignition,Emission}; %% 创建TestFile sltest.testmanager.clear; tf sltest.testmanager.TestFile([modelName _Tests.mldatx]); tf.FilePath fullfile(pwd,TestArtifacts); %% 配置覆盖率 cov getCoverageSettings(tf); cov.MetricSettings dmc; cov.SaveCoverageData true; %% 创建分类TestSuite for i 1:length(testCategories) ts(i) createTestSuite(tf,testCategories{i}); end %% 为每个分类添加TestCase harnessMap containers.Map(... {FuelInjection,Ignition,Emission},... {{FI_Nominal,FI_Fault}, {IGN_Test1,IGN_Test2}, {EMS_Validation}}); for i 1:length(testCategories) currentHarness harnessMap(testCategories{i}); for j 1:length(currentHarness) tc createTestCase(ts(i),baseline,currentHarness{j}); setProperty(tc,Model,modelName); setProperty(tc,HarnessName,currentHarness{j}); end end disp(测试框架构建完成);这个脚本的特点是使用containers.Map管理测试用例映射支持动态分类扩展完整的错误预防机制8. 进阶技巧与性能优化8.1 并行创建加速对于超大型模型可以用parfor加速if license(test,Distrib_Computing_Toolbox) parfor i 1:100 % 并行创建逻辑 end else % 串行版本 end8.2 自动化验证脚本创建后建议运行验证脚本%% 验证TestFile结构 testFile sltest.testmanager.load(MyTestFile.mldatx); suites getTestSuites(testFile); assert(~isempty(suites),无TestSuite存在); %% 检查TestCase数量 totalCases 0; for i 1:length(suites) cases getTestCases(suites(i)); totalCases totalCases length(cases); end fprintf(共创建%d个TestCase\n,totalCases);这套验证机制帮我在多个项目中发现早期问题避免后续测试阶段返工。