2. TestStand执行模型与异常传播
要真正掌握TestStand的异常处理,必须先理解它的执行模型:谁在执行、执行到哪里、出错后错误往哪里走、谁有机会拦截它。TestStand并不是一个简单的“顺序执行器”,而是一个由序列文件(Sequence File)、序列(Sequence)、步骤(Step)和执行入口点(Entry Point)构成的分层执行体系。异常(运行时错误)正是沿着这个层级结构向上传播的,而On Error回调与RunState对象则是我们在传播路径上设置的“拦截点”和“状态观察窗口”。
一、执行模型:从入口点到步骤的四层结构
TestStand的执行模型可以自上而下分为四层:
- 序列文件:一个 .seq 文件,是组织单元,内部可包含多个序列。它本身不执行,只是容器。
- 序列:真正被调用的执行单元,分为普通序列和入口点序列。入口点序列是TestStand引擎在特定时机自动调用的“钩子”,例如
MainSequence、ProcessSetup、ProcessCleanup、Setup、Cleanup等。 - 步骤:序列内的最小执行单位,每个步骤有类型(如 Numeric Limit Test、Sequence Call、Message Popup、Statement 等)、属性和运行结果。
- 步骤模块:步骤实际调用的代码(LabVIEW VI、C DLL、.NET 程序集、Python 脚本等),是错误真正产生的地方。
当测试启动时,TestStand引擎按顺序调用入口点:先执行 ProcessSetup,再对每个待测单元(UUT)执行 Setup → MainSequence → Cleanup,最后执行 ProcessCleanup。这个调用链就是异常传播的“主干道”。
二、运行时错误的传播路径
错误在TestStand中是一个结构化的数据对象,包含 Code、Msg、Source、Occurrence 等字段。当某个步骤模块返回错误时,传播遵循以下规则:
- 步骤级:步骤执行后,TestStand检查其返回的错误簇。若
status为真(出错),该步骤被标记为 Error。 - 序列级:默认情况下,序列遇到错误步骤会停止后续步骤的执行,并将错误向上返回给调用者。但序列的
Run Mode可设为Normal、Skip或Force Pass,影响是否继续。 - 调用链级:如果错误发生在被
Sequence Call调用的子序列中,错误会沿调用栈逐层向上返回,直到被某个 On Error 回调拦截,或到达顶层入口点。 - 入口点级:若错误一直未被处理,最终会传递到
MainSequence的调用者,TestStand会将UUT标记为失败,并继续执行Cleanup和ProcessCleanup(除非配置为中止)。
三、On Error回调:异常处理的拦截器
TestStand提供了多个层级的 On Error 回调,它们本质上是特殊的序列,在错误发生时被自动调用:
- SequenceFilePostStepOnError:步骤出错后立即调用,可访问出错步骤的上下文。
- SequenceFilePostStepRuntimeError:专门处理运行时错误(Runtime Error),比通用On Error更具体。
- SequenceFilePostSequenceOnError:序列执行出错后调用。
- ProcessModelPostStepOnError:在过程模型层级拦截,影响整个测试流程。
这些回调的典型用途包括:记录错误日志、决定是否重试、清理资源、将错误转换为警告、或强制继续执行。回调内部通过 RunState 对象获取错误详情和当前执行状态。
四、RunState对象:异常处理的状态中枢
RunState 是TestStand运行时暴露给回调的核心对象,它携带了当前执行的全部上下文。在异常处理中,最常用的属性包括:
| 属性/方法 | 作用 |
|---|---|
RunState.Error | 当前错误对象,包含 Code、Msg、Source 等 |
RunState.PreviousStep | 出错的前一步骤引用 |
RunState.NextStep | 下一步骤引用,可用于跳过或重定向 |
RunState.Sequence | 当前序列引用 |
RunState.Execution | 当前执行对象,可访问UUT信息、循环索引等 |
RunState.Caller | 调用者信息,用于追溯调用链 |
通过 RunState.Error 可以读取错误码和消息,通过 RunState.NextStep 可以修改执行流(例如跳过失败步骤继续测试),通过 RunState.Execution 可以获取当前UUT的序列号等标识信息,用于生成精确的错误报告。
五、一个典型的异常处理场景
假设我们在 MainSequence 中调用了一个子序列 TestVoltage,该子序列内部有一个 Numeric Limit Test 步骤,测量值超出上限,步骤返回错误。传播过程如下:
- 步骤模块返回错误,步骤被标记为 Error。
TestVoltage序列默认停止,错误向上返回。MainSequence中的Sequence Call步骤收到错误,MainSequence也停止。- 此时
SequenceFilePostStepOnError回调被触发,我们可以在其中读取RunState.Error.Msg,判断错误码是否为“电压超限”。 - 如果是预期内的超限,我们可以将错误记录到数据库,并设置
RunState.NextStep跳过后续电压测试,继续执行其他测试项。 - 如果不是预期错误,则保持错误状态,让UUT最终判定为失败。
这个场景说明:On Error回调不是简单地“捕获异常”,而是结合RunState对象,对错误进行分类、决策和重定向。这正是TestStand异常处理机制的核心价值。
六、实践中的关键配置与判断
在实际项目中,要让异常处理按预期工作,需要关注几个配置点:
- 序列的 Run Mode:在序列属性中设置
Run Mode为Normal(默认,出错停止)、Skip(跳过该序列)或Force Pass(强制通过)。这决定了错误是否继续向上传播。 - 步骤的 Run Mode:单个步骤也可设置
Run Mode,例如将某个非关键步骤设为Force Pass,即使出错也不影响整体流程。 - On Error 回调的启用:在序列文件属性中勾选对应的回调,并确保回调序列内部逻辑正确。回调中通常使用
RunState.Error判断错误类型,用RunState.NextStep控制后续执行。 - 错误处理策略:常见策略包括“记录并继续”、“重试N次”、“跳转到清理步骤”、“中止测试”等。选择哪种策略取决于测试项的重要性和错误性质。