在实际诊断测试项目中,0x3E服务(TesterPresent,测试仪在线保持)常被认为是UDS协议里最容易实现的服务:请求格式固定、响应逻辑简单、平时跑功能时几乎不会报错。但真正进入用例设计阶段时,很多人会卡住——周期怎么测?抑制响应位要测哪些场景?S3Server超时算谁的职责?如果需求里只写了“支持0x3E服务”,测试用例到底该从哪下手?
本文以“根据需求设计0x3E服务测试用例”为主线,先回顾0x3E服务在ISO 14229中的报文细节和S3Server会话保活机制,再给出从需求条目拆解到用例设计的完整方法,并提供一套覆盖正常、异常、边界、会话状态机、组合场景的0x3E用例模板。最后补充基于CANoe的CAPL自动化实现思路和常见问题排查清单。
内容面向车载诊断测试工程师、嵌入式ECU开发人员和刚接触UDS协议栈的新手。后面所有用例都可以直接复制到自己的用例管理系统或Excel模板中,再根据项目实际诊断规范做调整。
1. 0x3E服务是什么,为什么需要认真设计用例
1.1 从一个“保活”需求说起
在UDS(Unified Diagnostic Services,统一诊断服务)诊断体系中,ECU通常会维护一个会话定时器S3Server。只要ECU处于非默认会话(例如扩展诊断会话、编程会话),必须在规定时间窗口内收到来自诊断仪的任意诊断请求,否则ECU会认为诊断仪已离线,自动从当前会话退出,回到默认会话。
这样一来,诊断仪在长时间执行刷写、标定或数据采集时,就必须周期性地发送一个“我还在线”的信号来重置S3Server定时器,这个信号就是0x3E服务。
0x3E服务的作用可以概括为一句话:在不执行其他诊断功能时,保持诊断仪与ECU之间的会话连接。
1.2 0x3E服务在ISO 14229中的定义
ISO 14229-1中,0x3E服务被定义为TesterPresent,属于UDS应用层服务。它不携带数据参数,只包含一个子功能字节。客户端发送0x3E请求后,服务端根据子功能决定是否回复。
从功能上看,0x3E服务本身不读取ECU数据,也不修改任何参数,因此逻辑看起来很简单。但正是因为它简单,很多测试设计人员会低估它的测试价值:凡是涉及到会话状态切换、超时定时器、最小响应时间、总线负载的测试,最终都会回归到0x3E服务是否正确工作。
1.3 为什么0x3E服务的用例设计容易被低估
0x3E服务的用例设计之所以需要单独梳理,主要有三个原因:
第一,它与ECU的会话状态机强耦合。0x3E能否被正确响应,取决于当前会话、子功能支持表以及ECU的会话定时器配置。
第二,它存在“抑制肯定响应”这一特殊机制。0x80子功能表示服务端不应发送肯定响应,但否定响应不受抑制。不少测试人员会把“无响应”误判为“未收到0x7E就是失败”,忽略了抑制响应位的语义。
第三,它最容易在自动化测试中产生误报。因为0x3E请求通常周期性地出现在总线上,测试脚本如果过滤条件不严,很容易把周期保活报文当成其他服务的前置响应进行错误关联。
因此,即使0x3E服务代码量很少,在诊断测试中仍值得专门设计一套覆盖正常、异常、边界、状态迁移和组合场景的用例集合。
2. 0x3E服务核心原理回顾
在动手设计用例之前,先快速回顾0x3E服务的报文格式、子功能定义、S3Server超时机制和否定响应规则。这部分是所有用例预期结果的依据。
2.1 请求报文格式
0x3E请求格式如下:
| 字节 | 名称 | 值 | 说明 |
|---|---|---|---|
| Byte 0 | SID | 0x3E | TesterPresent服务ID |
| Byte 1 | 子功能 | 0x00 或 0x80 | 0x00表示需肯定响应;0x80表示抑制肯定响应 |
请求长度为2字节。超过2字节或只有1字节,都属于格式错误。
2.2 响应报文格式
当子功能为0x00且服务执行成功时,ECU返回肯定响应:
请求:3E 00 响应:7E 00当子功能为0x80时,服务端抑制肯定响应,总线上不应出现0x7E 0x80:
请求:3E 80 响应:无注意,0x80子功能只是抑制“肯定”响应,并不抑制“否定”响应。如果0x3E请求本身不合法,即使子功能为0x80,ECU也必须发送否定响应。这一点在ISO 14229-1中有明确说明。
2.3 子功能与抑制响应位
子功能字节的最高位是抑制肯定响应标志位(suppressPosRspMsgIndicationBit),bit6-0是真正的子功能编号。
- 0x3E 00:bit7=0,不抑制肯定响应,子功能为0x00。
- 0x3E 80:bit7=1,抑制肯定响应,子功能为0x00。
也就是说,0x3E其实只有一个实际子功能编号0x00,但它有两种请求形式:需要响应和不需要响应。
理解这一点非常关键。在需求文档中,通常会看到两条需求:
- “支持子功能0x00,返回肯定响应。”
- “支持请求子功能0x80,抑制肯定响应。”
这两条实际上是同一个子功能在抑制标志位上的两种表现,用例设计时既要分开验证,也要保证两者不冲突。
2.4 S3Server会话超时机制
S3Server的值通常根据OEM规范定义,常见默认值为5000ms。ECU处于非默认会话时,S3Server定时器被启动;每收到一个诊断请求,定时器重置;如果定时器超时,ECU回到默认会话。
0x3E服务的核心价值就在这里:它通过周期性发送请求,不断重置S3Server定时器,从而让ECU保持在当前会话。
这里还有一个容易混淆的点:S3Server定时器是所有诊断请求都会重置,还是只有0x3E能重置?实际上,ISO 14229规定,在非默认会话中,任何诊断请求都会重置S3Server定时器,0x3E只是其中最常用、最轻量的一种保活手段。因此用例设计时,可以考虑“发送其他诊断服务也能保活”这一场景,但不一定作为0x3E服务的强制需求。
2.5 0x3E服务相关的否定响应码
0x3E服务可能返回的否定响应码主要有:
| NRC | 含义 | 触发条件 |
|---|---|---|
| 0x12 | 子功能不支持 | 子功能编号不为0x00时 |
| 0x13 | 报文长度或格式错误 | 请求长度不为2字节 |
| 0x22 | 条件不满足 | ECU当前状态不允许执行该服务 |
| 0x7E | 服务不支持 | ECU完全未实现0x3E服务(少见) |
在大多数ECU中,0x3E服务在所有会话下都支持,因此0x22和0x7E的触发场景需要依据具体ECU诊断规范。设计用例前,先查当前项目诊断规格书中0x3E的支持会话表和支持子功能表。
3. 从需求到用例的设计思路
3.1 需求条目的层级拆分
测试用例不能直接从一个模糊的“支持0x3E服务”需求跳出来,应该先做需求拆分。一个完整的需求描述通常包含:
- 服务ID
- 支持的会话范围(默认、扩展、编程)
- 支持的子功能
- 肯定响应行为
- 否定响应行为
- 与其他服务/状态的交互约束
- 时序/周期要求
举个例子,假设原始需求是:
ECU应支持TesterPresent服务,用于在非默认会话中保持诊断会话连接。
按上面维度拆解后,可以得到至少6条可测试需求:
| 需求ID | 需求描述 |
|---|---|
| REQ-3E-001 | 在默认会话下,ECU应响应0x3E 0x00请求,返回0x7E 0x00 |
| REQ-3E-002 | 在扩展会话下,ECU应响应0x3E 0x00请求,返回0x7E 0x00 |
| REQ-3E-003 | 在编程会话下,ECU应响应0x3E 0x00请求,返回0x7E 0x00 |
| REQ-3E-004 | 当收到0x3E 0x80请求时,ECU应抑制肯定响应,不发送0x7E 0x80 |
| REQ-3E-005 | 当收到不支持的子功能时,ECU应返回NRC 0x12 |
| REQ-3E-006 | 在非默认会话下,周期发送0x3E请求应保持当前会话不超时 |
只有完成这样的拆解,后续用例设计才有明确依据。
3.2 用例设计方法选择
针对0x3E服务,最适合的方法组合是等价类划分、边界值分析和状态迁移测试。
等价类划分用于子功能字段:有效等价类是0x00、0x80;无效等价类是除0x00和0x80之外的所有值。注意0x80的高位置1后子功能编号仍然是0x00,因此不能简单地把0x80归为“无效”。
边界值分析用于时间周期:围绕S3Server超时时间设计发送周期,例如S3Server=5000ms时,可以选择周期为3000ms、4800ms、5000ms、5200ms、6000ms。周期明显小于超时时间时,会话应保持;周期大于超时时间时,会话应退出。
状态迁移测试用于会话状态机:覆盖默认会话→扩展会话→默认会话、默认会话→编程会话→默认会话等路径,验证0x3E在每个状态中的响应行为。
3.3 0x3E服务的测试分层模型
在实际项目里,我会把0x3E用例分成四层:
- 基础功能层:验证请求响应格式、子功能支持、NRC码。
- 会话管理层:验证0x3E在不同诊断会话中的行为,以及S3Server超时是否按预期触发。
- 边界与异常层:验证报文长度错误、总线上重复发送、总线负载、抑制响应位与NRC的组合行为。
- 组合场景层:验证0x3E与0x10(会话切换)、0x28(通信控制)、0x85(DTC设置控制)等服务的交互。
设计完一层再进入下一层,不会漏测试点,也方便分配用例优先级。
4. 0x3E服务用例设计实战
下面进入本文最核心的部分:一套覆盖正常、异常、边界、状态迁移、组合场景的0x3E服务测试用例。
4.1 用例编号与命名规范
建议用例编号格式为:
TC_服务ID_流水号_场景标识示例:
- TC_3E_001_DefaultSession_Positive
- TC_3E_002_ExtendedSession_SessionHold
- TC_3E_005_InvalidSubFunction_NRC12
这样做的好处是:看到用例编号就知道测的是什么服务、什么场景,并且方便在自动化测试报告中直接关联日志过滤条件。
每一条用例至少包含字段:
| 字段 | 说明 |
|---|---|
| 用例编号 | 全局唯一 |
| 需求依据 | 对应需求ID |
| 前置条件 | 诊断会话、ECU状态等 |
| 测试步骤 | 可执行的报文级步骤 |
| 输入数据 | 请求帧报文 |
| 预期结果 | 响应帧/状态变化 |
| 优先级 | P0/P1/P2 |
| 测试类型 | 功能/异常/边界/时序/组合 |
4.2 基础功能类用例
TC_3E_001 默认会话正常请求
- 需求依据:REQ-3E-001
- 前置条件:ECU上电,处于默认会话,总线通信正常
- 测试步骤:
- 发送UDS请求 0x3E 0x00
- 输入数据:
3E 00 - 预期结果:ECU在响应超时时间内回复
7E 00,且S3Server定时器被重置(如果当前在非默认会话) - 优先级:P0
TC_3E_002 扩展会话正常请求
- 需求依据:REQ-3E-002
- 前置条件:通过10 03进入扩展诊断会话
- 测试步骤:
- 发送UDS请求 0x3E 0x00
- 输入数据:
3E 00 - 预期结果:ECU回复
7E 00 - 优先级:P0
TC_3E_003 编程会话正常请求
- 需求依据:REQ-3E-003
- 前置条件:通过10 02进入编程会话(部分ECU需要额外解锁)
- 测试步骤:
- 发送UDS请求 0x3E 0x00
- 输入数据:
3E 00 - 预期结果:ECU回复
7E 00 - 优先级:P0
TC_3E_004 抑制肯定响应
- 需求依据:REQ-3E-004
- 前置条件:ECU处于默认会话
- 测试步骤:
- 发送UDS请求 0x3E 0x80
- 等待一个完整响应超时窗口(例如1秒)
- 输入数据:
3E 80 - 预期结果:总线上不出现
7E 80,但ECU内部应正常重置S3Server定时器 - 优先级:P0
TC_3E_005 不支持的子功能返回NRC 0x12
- 需求依据:REQ-3E-005
- 前置条件:ECU处于默认会话
- 测试步骤:
- 发送UDS请求 0x3E 0x01
- 发送UDS请求 0x3E 0x02
- 发送UDS请求 0x3E 0x7F
- 输入数据:
3E 01/3E 02/3E 7F - 预期结果:ECU对每组请求均回复
7F 3E 12 - 优先级:P0
TC_3E_006 报文长度错误返回NRC 0x13
- 前置条件:ECU处于默认会话
- 测试步骤:
- 发送长度仅为1字节的请求
3E - 发送长度大于2字节的请求
3E 00 00
- 发送长度仅为1字节的请求
- 输入数据:
3E/3E 00 00 - 预期结果:ECU回复
7F 3E 13 - 优先级:P1
注意,不同诊断仪、总线路由和ECU实现可能对多余字节的处理不一致。有的ECU会忽略多余字节并正常响应,有的则返回NRC 0x13。用例设计前先确认项目诊断规范中的描述,避免把规范允许的“忽略多余字节”误判为失败。
4.3 会话与超时类用例
TC_3E_007 周期发送0x3E保持扩展会话
- 前置条件:ECU处于扩展会话,S3Server=5000ms
- 测试步骤:
- 在扩展会话中,每隔3000ms发送一次
3E 00 - 持续发送6次,每次间隔3000ms
- 第6次发送后,再等待3000ms
- 发送一次
10 01(切换默认会话请求),观察ECU当前所在会话
- 在扩展会话中,每隔3000ms发送一次
- 输入数据:多帧
3E 00 - 预期结果:整个过程ECU保持扩展会话,S3Server未超时;最后发送10 01后返回
50 01 - 优先级:P0
TC_3E_008 停止发送0x3E后触发S3Server超时
- 前置条件:ECU处于扩展会话,S3Server=5000ms
- 测试步骤:
- 发送一次
3E 00确认当前会话正常 - 停止发送任何诊断请求,等待时间超过S3Server(例如6000ms)
- 发送一次
10 03请求进入扩展会话 - 观察ECU响应
- 发送一次
- 预期结果:等待超时后,ECU已自动回到默认会话;此时发送
10 03返回50 03,说明会话从默认重新进入扩展。相比未超时时直接发10 03,如果ECU本身处于扩展会话则返回NRC 0x22,这一区别可用于判断ECU是否真的发生了超时退出 - 优先级:P0
TC_3E_009 S3Server边界时间测试
- 前置条件:ECU处于扩展会话,S3Server=5000ms
- 测试步骤:
- 以4800ms周期连续发送10次
3E 00 - 每次发送后记录ECU响应和当前会话状态
- 再以5200ms周期连续发送10次
3E 00
- 以4800ms周期连续发送10次
- 输入数据:周期不同的
3E 00 - 预期结果:周期4800ms时ECU始终保持在扩展会话;周期5200ms时,某次发送后ECU会因定时器超时退出扩展会话,后续
3E 00响应行为按默认会话规则执行 - 优先级:P1
这里要特别说明:不同ECU对S3Server的计时精度、诊断仪请求处理耗时、总线调度延迟都有影响,边界值测试出现“有时超时、有时不超时”是正常的。用例结果应记录实际超时时间,作为ECU定时器精度评估依据。
TC_3E_010 0x3E 0x80同样重置S3Server定时器
- 前置条件:ECU处于扩展会话,S3Server=5000ms
- 测试步骤:
- 进入扩展会话后,每隔3000ms发送一次
3E 80 - 持续发送6次
- 最后一次发送后等待3000ms
- 发送
10 01验证当前会话
- 进入扩展会话后,每隔3000ms发送一次
- 预期结果:即使没有收到肯定响应,ECU的S3Server定时器仍然被
3E 80请求重置,会话保持扩展状态 - 优先级:P1
这条用例容易被遗漏。很多测试人员默认“无响应=没生效”,实际上0x3E 0x80只是不给应用层回响应,ECU内部服务照样执行,S3Server照样重置。
4.4 边界与异常类用例
TC_3E_011 子功能0xFF的处理
- 前置条件:ECU处于默认会话
- 测试步骤:
- 发送UDS请求 0x3E 0xFF
- 输入数据:
3E FF - 预期结果:ECU返回
7F 3E 12或按项目诊断规范定义处理 - 优先级:P2
TC_3E_012 重复发送相同请求
- 前置条件:ECU处于默认会话
- 测试步骤:
- 连续发送
3E 00三次 - 每次等待响应后再发下一次
- 连续发送
- 预期结果:每次均返回
7E 00,ECU无异常 - 优先级:P1
TC_3E_013 抑制响应位与否定响应优先级
- 前置条件:ECU处于默认会话
- 测试步骤:
- 发送UDS请求 0x3E 0x81(高位置1,子功能编号为0x01)
- 输入数据:
3E 81 - 预期结果:即便抑制响应位置1,由于子功能不支持,ECU仍应返回否定响应
7F 3E 12 - 优先级:P1
这条用例直接对应ISO 14229关于“否定响应不受抑制位控制”的规定,也是0x