0x28通信控制服务测试用例设计:从需求拆解到落地实践
0x28服务(CommunicationControl)是网络诊断里负责控制ECU通信状态的服务,在刷写、下线检测、OTA升级和售后诊断场景中出现频率很高。做0x28服务的用例设计时,最怕需求文档只写一句“刷写前禁止通信”,然后就等测试交用例。这句话落到测试层,包含子功能选择、通信类型位定义、会话条件、安全等级、响应是否可达、恢复机制、总线影响等多个维度,只要漏掉一个,用例评审时就会被挑战,更麻烦的是台架上测过了,却在实车暴露问题。这篇文章围绕0x28服务如何根据需求设计用例展开,先讲清服务和需求的语义,再按用例设计步骤、组合矩阵、工具辅助和排错链路逐层拆解。
1. 先搞清楚0x28服务到底控制的是哪些报文
1.1 三个常用子功能,先把语义定死
0x28服务的全名是CommunicationControl,中文常叫通信控制服务。它接收两个字节参数:子功能(subfunction)和通信类型(communicationType)。
在量产项目里,经常出现的子功能是这三个:
| 子功能 | 常见语义 | 典型用途 |
|---|---|---|
| 0x00 | 使能接收、禁止发送 | 让ECU静默,不主动发应用报文 |
| 0x01 | 使能接收、使能发送 | 恢复通信,结束0x28控制 |
| 0x02 | 禁止接收、使能发送 | 忽略某类报文,但还能正常响应诊断请求 |
必须提醒一句:不同OEM、不同协议版本对子功能0x02的语义定义可能存在差异。上表是项目里比较常见的理解,设计用例前一定要翻开需求文档或ISO 14229-1,把子功能的定义一个字一个字确认清楚。
为什么说这叫“把语义定死”?因为测试过程中很多争论都来自这里。我见过一条用例写“0x28禁止通信后,ECU不应再响应任何诊断请求”,这实际上把子功能、通信类型和服务本身的作用混在一起了。0x28控制的是ECU对外通信的发送和接收通路,不是“不响应该诊断请求”这么简单。禁止发送后,诊断请求能不能到达ECU,ECU还能不能处理诊断请求,取决于通信类型是否覆盖诊断报文,以及ECU软件对诊断报文的优先级定义。
1.2 通信类型里的位定义,决定用例矩阵的宽度
0x28服务第二字节是通信类型,常见实现中用位来表示控制范围:
| 位 | 含义 |
|---|---|
| bit0 | 应用报文(application messages) |
| bit1 | 网络管理报文(network management messages) |
| bit2 | 应用报文+网络管理报文(both) |
真正写进用例时,用0x01、0x02、0x03更常见。有些平台实现支持0xFF表示全部报文,这要看诊断规范是否允许。通信类型位定义直接决定用例数量:如果需求文档只允许0x02,那用例矩阵里就不能出现0x01;如果协议允许所有组合,你至少要为每种通信类型分别在“合法”和“非法”两侧设计用例。
这里有一个常见误判:很多人把“禁止通信”理解成“ECU没电了”,或者“ECU不再响应任何事情”,于是设计用例时认为发送0x28之后,ECU应该对任何操作都没有反应。真实情况复杂得多。0x28可能在禁止正常通信的同时依然接受诊断指令,尤其在设计上会保留诊断报文通道的ECU里。判断依据永远来自需求文档和诊断规范,不是来自直觉。
2. 用例开写前,先把需求拆成五个字段
2.1 一段需求通常要拆出这些信息
以一段常见需求为例:“刷写过程中,整车网络通讯复杂,部分ECU会产生周期报文干扰刷写,要求刷写前置步骤中先禁止目标ECU的应用报文发送,刷写完成后恢复通信。”
拆字段:
- 服务ID:0x28
- 子功能:禁止发送,通常是0x00或OEM自定义值
- 通信类型:应用报文,通常是bit0
- 会话条件:刷写一般在扩展会话或编程会话下进行
- 安全等级:部分安全策略要求安全解锁后才能执行0x28,部分只需要扩展会话
只写“刷写前禁止通信”的需求描述是非常薄弱的。用例设计者拿到这种描述,应该先整理一份需求问题清单,再动笔写用例,而不是直接套模板。
2.2 主动找齐这五个问题的答案
设计用例之前,我通常会先确认:
- 执行0x28是否需要安全解锁?未解锁时NRC是多少?
- 0x28执行的有效期是什么?是重启后失效、跳会话后失效、下发0x01后恢复、还是定时自动恢复?
- 禁止通信期间,ECU是否保留诊断响应通道?
- 禁止通信期间,相关DTC状态是否变化?
- 恢复通信的方式是诊断指令、下电重启、还是总线唤醒?
这几个问题里,第2个最容易踩坑。很多用例只写“下发0x28后,ECU不再发报文”,但没写“什么条件下恢复通信”。没有恢复条件,测试脚本执行完就停留在禁止状态,回归测试里会被反复质疑。
实际项目里,0x28的恢复条件往往和刷写流程强绑定。有些ECU设计成一旦进入默认会话,0x28的禁止状态立即解除;有些ECU则在任何会话下都保持,直到收到恢复指令或下电。需求文档如果没有写,一定要找系统工程师确认,而不是自己猜一个默认值写入用例。
注意:需求没有写恢复条件时,不要自己拍脑袋定一个“默认恢复”的逻辑。缺需求描述要先补需求,用例阶段不应该承担需求决策。
2.3 需求字段确认后做成一张需求解析表
推荐把需求解析结果做成一张表,既方便评审,也方便后续用工具生成用例。
| 需求点 | 需求描述 | 解析结论 | 用例设计影响 |
|---|---|---|---|
| 服务ID | 通信控制 | 0x28 | 服务级正反例 |
| 子功能 | 禁止发送 | 0x00 | 正向用例主路径 |
| 通信类型 | 应用报文 | bit0:0x01 | 组合范围受限 |
| 会话 | 扩展会话 | 0x03 | 默认会话必须设计NRC用例 |
| 安全 | 需要解锁 | 解锁后执行 | 未解锁用例预期NRC 0x33 |
我一般会在表里单独加一列“需求来源”,记录来自哪份文档的哪一页。后续排查用例争议时,这一列特别有用,可以直接翻到原始需求,而不是在群里反复讨论“当时到底是这么定的吗”。
3. 以刷写前禁止通信为主线,演示用例设计主流程
3.1 从主路径开始,不急着铺异常用例
用例设计最容易犯的错是从异常用例开始写。异常用例当然重要,但没有主路径用例做基线,评审时大家讨论的基线就不存在。先有一条能完整走通的用例,评审才能聚焦。
以“刷写前禁止目标ECU应用报文发送,完成后恢复”为例,主路径用例大概这样:
| 用例编号 | 前置条件 | 步骤 | 预期结果 |
|---|---|---|---|
| TC_CCT_001 | ECU上电,进入扩展会话,已解锁 | 发送0x28 00 01 | 收到正响应;ECU的应用报文停止;诊断报文可继续访问 |
| TC_CCT_002 | TC_CCT_001执行后 | 等待2秒 | ECU保持静默,应用报文不恢复 |
| TC_CCT_003 | TC_CCT_001执行后 | 发送0x28 01 01 | 收到正响应;应用报文恢复发送 |
| TC_CCT_004 | TC_CCT_001执行后 | 执行ECU下电再上电 | 应用报文在满足上电条件后恢复 |
这里的预期结果里,“诊断报文可继续访问”这个判断取决于ECU设计。如果ECU设计为0x28禁止应用报文时不阻止诊断响应,那正响应能收到;如果设计为诊断报文也属于控制范围,那正响应可能收不到。预期必须和需求文档一致,不能直接从通用模板抄。
注意:预期结果里写“诊断报文可继续访问”之前,先确认需求是否允许。很多测试脚本就是在这里卡死的,0x28把诊断通路也禁了,后面所有诊断步骤集体超时。
3.2 主路径跑通后再扩展条件
主路径用例跑通后,再按条件维度扩展。
子功能维度:在上面的基础上增加0x02(禁止接收、使能发送)用例。通信类型维度:在0x02的基础上增加网络管理报文控制用例。会话维度:检查默认会话下执行0x28是否被拒绝。安全维度:检查未解锁时执行0x28是否返回0x33。
这样扩展出来的用例才不是零散的“我想到什么就写什么”,而是有依据的覆盖。每条扩展用例都要基于前面那张需求解析表,不要脱离解析表单独发挥。
3.3 恢复机制用例不能只写一条
恢复机制是0x28用例设计里最容易被忽略的部分。很多用例只验证“禁止成功”和“恢复成功”两条,但实际刷写流程中,恢复失败的后果很严重:ECU保持静默,整车上电后网络管理异常,其他ECU无法唤醒它。
恢复机制至少要覆盖:
- 通过0x28 01恢复
- 通过下电重新上电恢复
- 通过会话切换恢复,如果设计如此
- 通过唤醒信号恢复,如果设计如此
- 恢复失败后的表现:ECU是否进入特定状态,是否记录DTC
每条恢复路径都要设计“恢复成功后再次发送0x28 00 01”的二次禁止用例,确认从恢复到禁止的来回切换没问题。状态型服务最怕只测单向流程。
4. 0x28服务用例矩阵:把需求拆成可组合的测试条件
4.1 合法组合用例矩阵
当需求文档允许的子功能是0x00、0x01、0x02,通信类型是0x01、0x02、0x03时,合法组合可以整理成矩阵:
| 子功能/通信类型 | 0x01(应用) | 0x02(网络管理) | 0x03(全部) |
|---|---|---|---|
| 0x00 禁止发送 | 应用报文停发 | NM报文停发 | 全部停发 |
| 0x01 恢复发送 | 应用报文恢复 | NM报文恢复 | 全部恢复 |
| 0x02 禁止接收 | 应用报文被忽略 | NM报文被忽略 | 全部被忽略 |
每条组合还需要叠加会话和安全条件。最简单的拆分方式是给每个组合单独复制四组用例:
- 默认会话 + 未解锁:预期NRC 0x7F
- 扩展会话 + 未解锁:预期NRC 0x33,如果安全策略如此
- 扩展会话 + 已解锁:预期正响应
- 编程会话 + 已解锁:有些OEM允许,需要单独确认
这样矩阵就从一个3×3扩展成3×3×4。每个单元格内还要考虑响应可达性和DTC行为。
4.2 异常用例矩阵
异常用例要覆盖协议层面和状态层面:
| 异常类型 | 请求内容 | 预期结果 |
|---|---|---|
| 子功能不支持 | 0x28 04 01 | NRC 0x12 |
| 通信类型非法 | 0x28 00 05 | NRC 0x13 或 0x31 |
| 长度错误 | 0x28 00 | NRC 0x13 |
| 未解锁 | 0x28 00 01 | NRC 0x33 |
| 会话不支持 | 默认会话执行 | NRC 0x7F |
这里有一个细节:子功能非法和通信类型非法的NRC可能因OEM实现而不同。0x28 00 05如果发生在已解锁且扩展会话下,有些ECU返回0x13,有些返回0x31。用例预期不能凭空指定,必须依据需求规格或OEM诊断规范,否则测试脚本会陷入“实际结果和预期不符”的争议。
4.3 时序类用例:连续、重复、间隔
0x28服务还有一个特殊点:它是带状态的。连续下发相同请求、在禁止状态中再次禁止、在恢复状态中再次恢复,行为都可能不同。
建议至少设计这些时序用例:
- 连续两次发送0x28 00 01:第二次是否返回正响应?是否影响状态机?
- 发送0x28 00 01后,间隔100ms发送0x28 01 01:间隔是否足够ECU完成切换?
- 在0x28 01 01恢复后,立即发送0x28 00 01:快速反转是否产生异常?
- 在0x28禁止状态中发送其他诊断服务:结果是否符合预期?
这些时序用例在自动化测试里特别有用,通常能用很少的成本暴露ECU状态机实现问题。实车问题里有一类就是快速反转操作触发的,台架回归却不一定会发现。
5. 用testbuddy这类用例生成工具时,提示词和模板要这样写
5.1 为什么不能直接写“生成0x28测试用例”
现在有人会用testbuddy这类用例生成工具来辅助出用例。工具本身不差,问题在于输入太笼统。直接让工具“生成0x28测试用例”,它很可能给你一份看起来完整、实际落地却没法执行的通用模板。
0x28服务的用例有效性和OEM规范强绑定,包括子功能范围、通信类型定义、安全策略、会话支持、响应可达性,这些信息工具无法自己猜。用工具前,必须先把需求拆成结构化描述输进去,工具才能基于规则补全条件。
5.2 一个可以直接参考的提示词结构
我第一次给AI辅助工具输入时,会这样拆分:
“请根据以下需求生成0x28通信控制服务测试用例。
服务ID:0x28 CommunicationControl 支持子功能:0x00 enableRxAndDisableTx,0x01 enableRxAndEnableTx,0x02 disableRxAndEnableTx 支持通信类型:0x01 应用报文,0x02 网络管理报文,0x03 全部 会话条件:0x28只能在扩展会话和编程会话下执行,默认会话不支持,NRC为0x7F 安全条件:执行0x28前需要安全解锁,未解锁NRC为0x33 恢复条件:0x28 01 01恢复,下电重新上电恢复,会话切换恢复 总线约束:禁止应用报文发送后,ECU仍应响应诊断请求 DTC约束:禁止通信期间不产生通信相关DTC 用例格式:包含用例编号、前置条件、步骤、预期结果”
实际使用testbuddy或类似工具时,把上面结构填进需求描述或提示词,生成结果才会更接近可评审状态。工具生成之后,还是要人工做专家评审,AI辅助生成用例的价值主要在于覆盖率补全和格式统一,它不能替代你对需求的理解。
注意:工具生成结果只能当初稿。没有经过需求评审的用例,不能直接作为测试依据进入执行阶段。
5.3 生成后的用例清单怎么验收
验收生成结果时,我习惯用这三条标准:
- 每条用例是否都有明确的前置条件,包括会话、安全状态、0x28初始状态?
- 预期结果是否写了“状态变化”,而不是只写“通过”?
- 恢复机制和异常条件是否覆盖?
满足这三条,再进入用例评审。不满足,就继续补充需求信息或调整提示词。不要把工具生成的结果当成最终交付物,它是草稿,不是结论。
6. 用例执行时容易翻车的场景和排查顺序
6.1 禁止通信后,诊断仪把自己玩断
0x28用例执行中最常见的问题:发送禁止通信指令后,诊断请求也发不出去了。这时候不要急着改脚本,先确认0x28的通信类型是否包含了诊断报文。如果包含了,测试工具需要先恢复通信,或者重新上电,否则后续所有诊断步骤都停留在超时状态。
实际项目里我遇到过一种情况:脚本发送0x28 00 03把诊断报文也禁止了,然后脚本继续发状态轮询,等待回复,结果一直超时。问题不在ECU,而在于测试用例没有设计“禁止期间诊断响应是否可达”这个前置条件。
遇到这种情况,排查顺序是:
- 先看0x28请求是否收到正响应。
- 再看测试工具能不能恢复通信,比如发送复位或0x28 01。
- 如果工具通信中断,优先下电重启,而不是反复发指令。
- 最后回查用例矩阵,确认禁止范围是否覆盖诊断报文。
注意:脚本里不要反复发送诊断请求来“试探”恢复,先确认是通信控制导致的中断,再执行恢复步骤。
6.2 网络管理报文被抑制后的总线异常
当0x28的通信类型包含NM报文时,情况更复杂。ECU不再发送NM报文后,整车网络管理的状态机可能认为该节点离线,产生唤醒状态异常或休眠异常,其他ECU会记录通信相关DTC。
这种问题不是0x28服务本身错误,而是测试场景没有隔离。执行这类用例时,建议在总线仿真环境里单独验证,避免在整车全网络环境里操作。如果一定要在实车上执行,需要提前确认整车网络管理策略,并准备恢复脚本。
6.3 恢复不彻底的错觉
有个隐蔽问题:发送0x28 01 01后,应用报文恢复了,但ECU的网络管理状态没有回到正常。原因是部分ECU在0x28禁止NM报文期间,网络管理状态机被强制置为Bus-Sleep或Prepare Bus-Sleep,恢复指令只恢复报文发送,不恢复状态机。
用例预期里必须区分“报文恢复”和“网络管理状态恢复”。如果能通过诊断读取ECU状态,最好把状态读取也写入步骤,否则你就只验证了表面现象。
6.4 台架和实车行为不一致
0x28在台架上很好用,但在实车上受网关路由、总线负载、电源管理影响,行为可能完全不同。比如网关可能不会转发0x28请求到目标ECU,导致指令实际上没有执行。排查时先抓总线报文,确认请求真的到达了目标ECU,再判断ECU行为。
我在台架验证通过后,一般会安排一版实车冒烟用例,专门覆盖:网关转发路径、整车上下电时序、网络管理状态恢复。这样可以提前暴露环境差异导致的问题。
7. 用例设计完成前,保留最后的自查清单
7.1 一份可以复印的检查清单
0x28用例设计完成后,我会按下面清单自查:
- 服务ID是否与需求一致?
- 子功能列表是否与需求文档一致?有没有把0x01误用成0x00?
- 通信类型范围是否覆盖需求允许的全部组合?
- 是否设计了默认会话下的NRC用例?
- 是否设计了未解锁场景下的NRC用例?
- 是否覆盖恢复机制:诊断指令恢复、下电恢复、会话切换恢复?
- 是否覆盖禁止期间诊断响应的可达性?
- 是否覆盖DTC影响?
- 是否覆盖状态快速反转场景?
- 是否在实车环境安排冒烟用例?
这个清单不是万能清单,但它能挡住0x28用例评审里最常见的十个问题。每次用例评审,我基本都是从这十项开始问。
7.2 落地时真正该盯住的不是功能列表
0x28服务说到底只是一个带状态的控制服务,真正的复杂度来自它和会话、安全、总线、网络管理、DTC之间的耦合。所以用例设计花大力气的地方,不应该是“列出了多少条用例”,而是有没有把这些耦合关系都写清楚。
如果只是学习一遍,默认矩阵可以这样起步:主路径、恢复、异常、时序,各写一组。如果要用于生产项目,就要回到OEM规范逐条核对。多花时间把需求和协议字段抠清楚,后面执行阶段会省掉很多无谓的返工。
