4. Stateflow测试用例设计基础

Stateflow的测试用例设计不能直接照搬纯软件的黑盒方法,因为它的“输入”不只是函数参数,还包括事件、超时、条件表达式和外部信号;它的“输出”也不只是返回值,而是状态激活、迁移触发、动作执行和输出数据更新。因此,经典方法在Stateflow中需要做一次“对象映射”:把等价类划分映射到事件与条件组合,把边界值分析映射到阈值与计时参数,把决策表映射到迁移条件与动作,把状态迁移覆盖映射到状态、迁移和路径的覆盖强度。

先看等价类划分。在Stateflow中,一个等价类通常由“输入区间 + 当前状态 + 事件类型”共同决定。例如一个简单的挡位控制Chart,输入为车速 v,状态为 Park、Drive、Reverse,事件为 shift。有效等价类可以是“在Drive状态下,v在0~120之间且收到shift到Reverse的请求”;无效等价类可以是“在Park状态下,v大于5时请求进入Drive”。设计时先列出每个状态下的有效与无效输入区间,再为每个等价类选取一个代表值。代表值不必是边界,但必须能唯一区分该等价类。

边界值分析在Stateflow中尤其重要,因为迁移条件几乎总是写成 v >= 30、t > 2.5 这类比较。对每个阈值,至少取三个点:阈值下、阈值上、阈值本身。若条件带等号,阈值本身属于“满足”一侧;若不带等号,阈值本身属于“不满足”一侧。例如迁移条件为 [v >= 30 && brake == 0],则边界点应取 v=29.9、v=30.0、v=30.1,并分别搭配 brake=0 与 brake=1。计时器边界同样要覆盖:after(2.5, sec) 应测试 2.4s、2.5s、2.6s,并确认事件在2.5s之前不触发、之后触发。

决策表适合处理“多个条件组合决定一个动作”的逻辑。Stateflow中常见的迁移条件往往由三到五个布尔条件组成,若直接穷举会产生大量冗余用例。决策表的作用是把条件组合压缩成有限规则,并明确每条规则对应的迁移目标或动作。例如一个车门锁控制逻辑,条件包括 speed > 0、doorClosed、lockRequest,动作包括 lock()、unlock()、noAction()。决策表可以写成如下形式:

规则speed > 0doorClosedlockRequest动作
R1是是是lock()
R2是是否noAction()
R3是否是noAction()
R4否是是unlock()
R5否否是noAction()

决策表生成后,每条规则至少对应一个测试用例。若某条规则在Stateflow中不可达,应标记为“不可达规则”并说明原因,而不是直接删除。不可达规则往往意味着模型存在冗余条件或设计缺陷,是测试中值得记录的对象。

状态迁移覆盖是Stateflow测试中最具结构性的方法。它至少包含四个层次:状态覆盖、迁移覆盖、迁移对覆盖和路径覆盖。状态覆盖要求每个状态至少被激活一次;迁移覆盖要求每条迁移至少被触发一次;迁移对覆盖要求每条迁移的“前驱迁移—后继迁移”组合至少出现一次;路径覆盖则要求从初始状态到目标状态的所有可行路径至少执行一次。实际项目中,迁移对覆盖通常是性价比最高的目标,因为它能发现“单条迁移正确但组合后出错”的问题。

下面这张图把上述四种方法在Stateflow中的适配关系集中呈现出来,左侧是经典方法,右侧是Stateflow中的具体测试对象与覆盖目标。

经典测试方法 → Stateflow 适配对象与覆盖目标 等价类划分 输入区间 + 状态 + 事件 有效 / 无效等价类 边界值分析 阈值 ± 步长 计时器 after 边界 决策表 条件组合 → 动作 规则可达性检查 状态迁移覆盖 状态 / 迁移 / 迁移对 / 路径 覆盖强度递进 Stateflow 输入空间 事件 shift / brake / timeout 数据 v / t / mode 迁移条件与计时器 [v >= 30 && brake == 0] after(2.5, sec) 迁移规则与动作 条件组合 → 目标状态 entry / during / exit 动作 状态与迁移图 状态节点 / 迁移边 / 默认迁移 层次化父状态与子状态 等价类代表用例 每个有效/无效类 ≥ 1 条 覆盖状态 × 事件组合 边界点用例 阈值下 / 阈值 / 阈值上 计时器提前 / 准时 / 超时 决策表规则用例 每条可达规则 ≥ 1 条 不可达规则单独标注 覆盖强度目标 状态 → 迁移 → 迁移对 → 路径 按风险选择覆盖等级 适配要点:Stateflow 的测试对象是“状态 + 事件 + 条件 + 计时”的组合,覆盖目标需同时考虑数据边界与迁移结构

把四种方法组合使用时,建议按以下顺序推进:先用等价类划分确定输入空间的基本分区,再用边界值分析补充每个分区的临界点,接着用决策表压缩多条件组合并检查规则可达性,最后用状态迁移覆盖检查结构完整性。这样得到的测试用例集既有数据层面的精度,也有结构层面的覆盖保证。

需要特别注意的是,Stateflow中的“默认迁移”和“历史节点”会改变路径覆盖的语义。默认迁移决定Chart首次激活时进入哪个子状态,历史节点决定重新进入父状态时是否恢复上次子状态。测试用例必须显式覆盖“首次进入”和“重新进入”两种情形,否则路径覆盖会存在盲区。例如一个带历史节点的 Drive 父状态,首次进入应走默认迁移到 Gear1,退出后再进入应恢复到 Gear3(若上次停留在Gear3)。这两条路径必须分别设计用例。

在Stateflow中,等价类划分的“类”不是单纯的数据区间,而是“状态 × 事件 × 条件”的三元组。设计时先画状态迁移图,再在每个状态上标注可接受的输入区间,最后为每个区间取代表值和边界值,可以避免遗漏跨状态的组合场景。

最后给出一个可直接参考的用例设计检查清单,用于在Stateflow模型上逐项核对:

  • 每个状态是否至少被激活一次?
  • 每条迁移是否至少被触发一次?
  • 每条迁移的前驱与后继组合是否至少出现一次?
  • 每个比较条件的阈值上、阈值、阈值下是否都有用例?
  • 每个计时器是否覆盖提前、准时、超时三种情形?
  • 决策表中每条可达规则是否至少对应一条用例?
  • 不可达规则是否已记录并说明原因?
  • 默认迁移和历史节点是否分别覆盖首次进入与重新进入?

完成上述检查后,测试用例集就具备了从数据边界到状态结构的双重覆盖能力,可以作为后续自动化测试和模型验证的输入基础。