ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UDS 0x85服务测试用例设计:从需求约束到状态时序覆盖

UDS 0x85服务测试用例设计:从需求约束到状态时序覆盖 前一阵评审同事的 0x85 服务测试用例一开始看起来挺完整请求报文长度、子功能 01/02、两个否定响应码都覆盖了。但往深一问DTC 设置关闭之后重新上电会不会恢复关闭期间故障是否还会记录要不要先切到扩展会话安全解锁失败时返回哪个 NRC用例表里一个都没有。这不是个例。做网络诊断测试久了就会发现0x85 服务这类功能型诊断服务真正的复杂度从来不在协议层的字节解析而在把需求里的状态、条件、时序翻译成可执行的用例。0x85 服务表面上是一个 DTC 设置控制开关实际上是一个会影响整个故障管理行为的状态机。所以“根据需求设计用例”这件事不能只照着 ISO 14229 抄而要把需求里的每条约束拆开、落到输入和预期结果里。我的核心判断是0x85 服务的用例设计重点不在服务响应是否正常而在需求里的会话约束、安全约束、时序约束和存储约束是否被完整覆盖。1. 先别急着设计用例搞清楚 0x85 服务真正控制的是什么1.1 它控制的是 DTC 的“记录开关”不是故障灯开关在 UDS 诊断协议里0x85 服务通常叫 ControlDTCSetting翻译过来是“控制 DTC 设置”。它要控制的不是故障灯也不是故障码存储文件而是 ECU 对 DTC 状态位的更新行为。在常见实现中DTC 状态字节会包含 testFailed、confirmedDTC、pendingDTC 这些状态位。正常情况下ECU 检测到故障后会按照故障管理逻辑更新这些状态位。0x85 服务关闭 DTC 设置后ECU 不再响应新的故障事件不再继续把 pendingDTC 或 confirmedDTC 置位。但这里有个关键点它不等于清空 DTC。已经置位的 DTC 状态通常仍然保留清 DTC 是 0x14 服务 ClearDiagnosticInformation 的职责。很多新人会把 0x85 服务理解成“关闭故障码功能”一旦 DTC 设置了关闭就以为所有故障现象都应该消失。这个理解在测试用例设计里很危险。因为如果需求明确写了“关闭 DTC 设置后DTC 状态位保持不变、故障灯保持点亮”那测试预期就要按这个来写而不是想当然地认为故障灯会熄灭。设计用例的第一步是先确认需求要求“关闭”到什么程度是停止记录新故障还是同时停止故障灯点亮还是连已存储的故障状态也被冻结。还有一个容易混淆的点是设置状态本身。0x85 服务执行成功后DTC 设置状态是开启还是关闭需求里通常会定义。但这个状态是不是掉电保持是存在 RAM 还是 NVM 里不同 ECU 差异很大。有的 ECU 下电重启后会恢复为“开启”有的会保持在“关闭”。如果不把这个状态作为用例设计的一部分后面测试很容易出现“响应正确但行为错误”的争议。1.2 请求与响应里的三个关键字段设计 0x85 服务用例至少要把请求和响应结构里的字段拆清楚。0x85 服务的请求通常由三部分组成服务 ID 0x85、子功能、DTCSettingControlOptionRecord。子功能在通用协议里常见定义是 0x01 表示开启 DTC 设置0x02 表示关闭 DTC 设置。具体到某个 OEM 规范子功能码可能不同甚至可能增加更细的自定义类型。所以用例设计不能只看 ISO 14229还要看项目里的诊断规范。DTCSettingControlOptionRecord 是更值得重视的字段。它有几种情况请求里不携带请求里携带固定长度数据请求里携带可变长度数据。需求里如果定义了 option record用例就要覆盖正确的 record 值能得到肯定响应错误的 record 值应该返回对应 NRCrecord 长度比规范定义多一字节或少一字节ECU 的响应是否符合预期重复发送相同 record结果是幂等还是会被拒绝。一个 CAN 单帧请求的示例大致是这样诊断请求 02 85 01 # 0x85 服务子功能 0x01无 option record 肯定响应 02 C5 01 # 0xC5 0x85 0x40子功能原样回显 否定响应示例 03 7F 85 33 # 服务 0x85NRC 0x33常见含义是安全访问未通过这个示例只是常见形态具体报文长度和 option record 内容以项目诊断数据库为准。响应这边肯定响应会回显 SID 和子功能如果 option record 有定义也可能回显 record。否定响应则是 0x7F 0x85 NRC。用例设计时需要把每种 NRC 的触发条件都对应到具体输入而不是只留一个“返回错误码”的模糊预期。2. 从需求到用例先建立一个可翻译的约束矩阵2.1 需求文档里经常出现的四类约束0x85 服务的需求很少只写一句“支持 0x85 服务开启和关闭 DTC 设置”。真实项目里需求会分布在不同章节里如果不逐条拆很容易漏用例。最常见的是会话约束。比如“仅扩展会话支持该服务”或者“默认会话下该服务应返回 NRC”。这类约束决定了用例的前置会话状态。第二类是安全约束。很多 ECU 会要求安全访问解锁后才能执行 0x85 服务尤其关闭 DTC 设置这种会影响故障诊断的功能。需求里可能写着“安全等级 2 解锁后允许执行”也可能写“未解锁时执行应返回 0x33”。这类需求要转化为“是否解锁 请求 预期响应”的用例组合。第三类是车辆条件约束。部分 ECU 会限制在车辆运行状态下不允许关闭 DTC 设置或者车速超过某个阈值时不响应。这类约束在台架测试里容易忽略因为台架默认供电稳定很难意识到实车还有车速、挡位、充电状态这些条件。第四类是存储和恢复约束。这是 0x85 服务需求里最容易出问题的地方。需求里可能定义“关闭状态在下电后保持”也可能定义“退出扩展会话后自动恢复为开启”。这两类约束如果没写清测试执行时一定会产生分歧。用例设计阶段就要把这一条找出来不能等测试执行时再靠猜。2.2 三步法从需求条目到用例编号我一般会把“从需求到用例”的过程固定成三步避免一上来就直接写步骤。第一步把需求拆成单一条件的条目。一条需求如果包含“扩展会话 安全解锁 关闭 DTC 设置 下电后恢复”四个内容就要拆成至少四条独立用例而不是一条大用例。因为如果测试失败你很难定位是哪个条件没满足。第二步把每个条件映射成测试前置条件和输入。比如“未解锁时执行 0x85 关闭”对应的前置条件是安全访问未完成输入是 0x85 02预期结果是 NRC 0x33。这一步其实是在翻译需求把模糊的描述变成可执行的操作。第三步把这些映射结果整理成用例矩阵。矩阵里至少包含需求编号、前置条件、请求输入、预期响应、用例优先级。这样后续评审时可以逐行核对而不是在几十条用例里靠肉眼找遗漏。不要一上来就想着把用例数量做满。先把需求拆出的条件一条条列出来条件没拆完数量再多也说明不了覆盖率。2.3 一个可落地的需求-用例映射表下面是一个示例结构不是某个 OEM 的真实需求。它用来展示映射表应该长什么样。需求描述前置条件请求输入预期结果用例类型默认会话下不允许执行 DTC 设置控制默认会话未解锁0x85 01否定响应预期 NRC 由规范定义否定路径扩展会话且安全解锁后允许关闭 DTC 设置扩展会话已安全解锁0x85 02肯定响应 0xC5 02状态变为关闭正常路径关闭 DTC 设置后再次执行关闭应保持关闭扩展会话已解锁DTC 设置状态为关闭0x85 02肯定响应状态仍为关闭不产生新 DTC幂等路径关闭 DTC 设置后重新上电应恢复为开启扩展会话已解锁DTC 设置已关闭下电再上电状态恢复为开启时序路径未解锁时执行关闭应拒绝扩展会话未解锁0x85 02NRC 0x33 或规范定义错误码否定路径这张表的价值在于每条用例都有前缀条件和预期结果评审时能很快看出某条需求有没有被覆盖。如果需求变更比如把“重新上电恢复为开启”改成“上电保持关闭”只需要在表里定位对应行就能找出所有受影响用例。3. 用例设计核心功能路径、否定响应、状态时序3.1 功能路径设计正常开关并不是一种路径很多测试用例只写两条正常路径发送 0x85 01 成功发送 0x85 02 成功。但在 0x85 服务里“成功”不代表行为正确。更完整的正常路径至少应该覆盖这些组合当前 DTC 设置状态为开启时发送关闭请求当前状态为关闭时再发送关闭请求验证幂等当前状态为关闭时发送开启请求当前状态为开启时再发送开启请求连续多次发送同一请求观察 ECU 是否稳定带默认 option record 请求与不带 option record 请求确认响应是否一致如果规范允许 record覆盖最小长度、最大长度和正常长度。设计这些路径时不能只看响应报文。如果条件允许应该在每次请求后再通过诊断服务读取 DTC 状态或者读取 DTC 设置状态。否则可能出现“响应正确但状态没变”的情况。这个现象在 0x85 服务测试里并不少见尤其是需求里定义了延迟生效或条件不满足但 ECU 先返回肯定响应的情况。3.2 否定响应设计按 NRC 矩阵覆盖而不是“挑几个”0x85 服务可能的否定响应码不能凭感觉选应该按需求文档和诊断数据库列出的 NRC 一一设计。常见的 NRC 触发条件大致如下NRC常见触发原因用例设计建议0x12子功能不支持发送需求未定义的子功能例如 0x00、0x030x13消息长度错误请求缺少子功能或 option record 长度与规范不一致0x22条件不正确在禁止条件下请求例如车辆状态不满足0x31请求超出范围发送规范未定义的 option record 值0x33安全访问失败或未解锁未执行安全访问直接请求0x7E当前会话下不支持该子功能在默认会话请求受限子功能0x7F当前会话下不支持该服务在默认会话请求 0x85 服务设计否定路径用例时要特别注意触发条件本身是否可执行。比如 0x22 条件不正确如果需求里写得比较模糊没有说清什么条件下允许、什么条件下禁止用例就无法稳定触发。这时应该先和需求方澄清而不是在用例里写“发送请求返回任意 NRC”。还有一个容易被忽略的细节同一类错误输入在不同会话里可能返回不同 NRC。比如默认会话下发送不支持的子功能有些 ECU 会返回 0x12有些会先判断会话返回 0x7E。用例如果只在扩展会话下覆盖一遍默认会话的情况就会漏掉。3.3 状态时序设计最容易遗漏的恢复场景0x85 服务用例里最有价值的一部分是这个 H2 要讲的时序路径。因为它不是简单验证一次请求而是要验证状态管理行为。至少有几条时序场景值得固定进用例集关闭 DTC 设置后造一个真实故障条件等待超过 pendingDTC 的记录时间确认 DTC 状态位不变化关闭 DTC 设置后执行 0x14 清除 DTC再重新开启 DTC 设置确认新故障是否会被记录关闭 DTC 设置后退出扩展会话并重新进入确认 DTC 设置状态是否自动恢复关闭 DTC 设置后重新上电确认状态是按 RAM 还是 NVM 恢复关闭 DTC 设置后安全解锁状态因为重新上电而失效再次执行关闭请求确认是否需要重新解锁开启 DTC 设置状态下连续执行关闭和开启确认状态切换过程中没有残留状态。测试过程中最怕的不是 NRC 返回得不对而是成功响应后 ECU 内部状态没有变化。这个问题通常需要靠读取 DTC 状态或故障注入来暴露只靠响应帧判断会得出错误结论。时序用例的预期结果必须来自需求描述而不是测试人员的经验。比如“退出扩展会话后DTC 设置状态恢复为开启”和“退出扩展会话后保持关闭”在协议层面都是可能的区别只在 OEM 需求和 ECU 设计。如果需求没写清楚应该把它记录为需求缺陷而不是用自己猜的结果去填预期。4. 用例生成工具TestBuddy 类能帮你什么、不能帮你什么4.1 工具生成用例的原理与价值现在不少诊断测试团队会用 TestBuddy 这类用例管理或生成工具来辅助设计用例。尤其当车型项目里有多个 ECU每个 ECU 的诊断需求都很长时靠人工逐条写用例效率太低。工具生成的逻辑通常是基于诊断需求或诊断数据库把服务 ID、子功能、会话、安全等级、NRC 列表这些结构化信息提取出来自动展开成基础用例。这样做的好处很明显可以快速覆盖“SID 子功能 会话 安全等级 NRC”的笛卡尔积减少人工漏项。对 0x85 服务来说工具能帮你快速生成所有子功能和 NRC 的组合这是手工表格最容易遗漏的部分。比如子功能开了、关了、不支持、保留每个组合都可能有不同响应。用工具一次性铺开再人工筛选效率高很多。但工具生成的用例通常只是骨架。骨架的意思是它知道“发送 0x85 02 应该返回肯定响应”但它不知道“发送 0x85 02 前需要先保证车速低于某个阈值”更不知道“关闭 DTC 设置后是否要在下电前再验证一次状态保持”。这些内容来自需求文本而需求文本里的条件往往没有结构化到工具能直接读取的程度。4.2 生成之后必须人工补的检查项用 TestBuddy 或类似工具生成完用例我会建议按下面这几项做一轮人工审查而不是直接把生成结果导入执行平台。第一检查前置条件是否可执行。工具生成的用例通常会写“安全解锁后执行”但它不会告诉你安全解锁的具体流程、解锁等级和超时时间。这些必须人工补全否则执行用例的人拿到的是不完整信息只能现场猜。第二检查状态验证方式。0x85 服务的用例不能只验证响应帧还要验证 ECU 内部状态。工具很难自动判断“用哪个 DID 读取 DTC 设置状态”因为不同 ECU 的状态地址、数据格式都不一样。第三检查时序场景。工具对状态的迁移、掉电恢复、会话退出恢复这些场景生成能力普遍有限。这不是工具缺陷而是这些行为很难从静态诊断数据里推断出来只能靠人工从需求文本里提取。第四检查预期结果是否可测量。如果预期结果写着“DTC 设置状态正确”但没写清楚是用响应判断还是用状态读取判断这条用例将来执行时很难判定通过还是失败。人工审查时要把这类模糊预期改成可观测、可对比的结果。工具生成的用例只是骨架。真正决定测试有效性的是人工补进去的前置条件和预期结果。5. 执行 0x85 服务用例时的前置条件与排查思路5.1 执行前先确认环境与诊断数据0x85 服务测试看起来是简单的诊断请求但执行前需要确认的环境项并不少。第一步确认诊断数据库。用 ODX、CDD 或项目内部的诊断调查表核对 0x85 服务的会话、安全等级、子功能、option record 长度。如果数据库和需求文档不一致不能直接测要先把差异处理掉。第二步确认总线环境和供电方式。台架测试里ECU 供电通常稳定但实车上有上下电时序、网络管理、总线休眠。如果需求包含“下电后恢复”这种场景测试环境最好能模拟下电和上电不能只停留在连续发送诊断请求的层面。第三步确认 DTC 状态读取路径。执行 0x85 服务后如何确认状态真的变了一般可以通过 0x19 服务读取 DTC 状态或通过某个 DID 读取 DTC 设置状态。如果没有这个验证通道测试执行时很容易陷入“响应正常但不知道是否生效”的困境。第四步把日志记录做好。0x85 服务用例最怕的是执行结束后没有请求帧、响应帧和时间戳。后续一旦发现结果有问题只能重测。建议每次用例都保留完整日志至少包含时间、方向、CAN ID、数据场、NRC。5.2 一条可复用的排查链路如果执行过程中出现问题建议按这个顺序排查不要一上来就怀疑 ECU 实现。先看现象。是完全没有响应还是返回了否定响应还是肯定响应但状态没变。现象不同排查方向完全不同。再看请求帧。从日志里把原始报文贴出来核对 SID 是否是 0x85子功能是否写对option record 长度是否和规范一致。很多问题是脚本里字节写错导致的。再看当前会话。0x85 服务通常对会话有要求。如果当前在默认会话请求被拒绝是正常的。切换到扩展会话或编程会话后再试往往就通过了。再看安全状态。如果请求前没有执行安全访问或者安全访问超时返回 0x33 是正常行为。需要确认测试步骤是否遗漏了解锁流程。再看条件。如果返回 0x22 条件不正确要检查是否达到速度阈值、电源状态、整车上下电状态等条件。最后再看内部状态。如果肯定响应也正常条件也满足但 DTC 仍然被记录通常要检查 DTC 设置状态是否真的存在非易失存储里。曾经遇到过一个现象0x85 02 返回成功但重新上电后 DTC 又继续记录原因是该 ECU 的 DTC 设置状态只存在 RAM 中掉电即失效。而需求里并没有明确要求保持最终是需求缺陷不是软件缺陷。这条链路写出来是为了提醒排查问题时先确定是哪一层出了问题再决定改哪里。顺序反了往往会因为一个字节长度错误浪费半天时间。5.3 从测试报告反推用例质量测试执行完成后可以反过来看报告质量。如果一份 0x85 服务的测试报告全部是通过且用例数量很少那并不一定说明 ECU 稳定也可能是用例设计得不够深。我会关注几个信号否定路径用例数量是否和 NRC 列表匹配有没有时序恢复类用例有没有状态验证步骤有没有失败或需要澄清的项。如果这些信号都是空白说明用例很可能只覆盖了协议层正常路径。6. 长期角度看 0x85 服务用例设计的价值6.1 用例质量要看需求变更后的回归能力0x85 服务的用例设计不是一次性工作。项目开发过程中需求一定会变。比如安全等级从 Level 1 改成 Level 2或者 DTC 设置状态的掉电策略从“恢复为开启”改成“保持关闭”这些变更会对用例集造成连锁影响。如果用例设计从一开始按需求矩阵组织起来需求变更后只需要把变更条件对应的行找出来列出相关用例就能快速完成回归。如果用例是按协议字段组织起来的没有和需求条目关联变更影响分析就会变成人肉排查漏项风险很高。这也是为什么我一直强调0x85 服务用例的重点不是“服务响应对不对”而是“需求里的约束有没有被拆出来、有没有落到用例上”。真正有价值的用例是和需求条目能够双向追溯的用例。6.2 给新人的一条建议如果你刚开始做诊断测试我建议不要从协议文档开始设计 0x85 服务用例而是从需求文档开始。先把需求里和 DTC 设置状态相关的每一句话都找出来拆成条件再对照协议理解请求和响应最后才轮到写具体步骤。哪怕用 TestBuddy 这类工具自动生成了一部分用例人工分析这一步也不能省。工具能帮你把表格铺开但不能替你理解“下电后恢复”“退出会话后恢复”“安全解锁超时”这些行为和真实故障管理逻辑的关系。0x85 服务测试没有太多高深算法它的门槛在于愿不愿意把需求当作状态机去拆。把开关、条件、恢复路径都放进用例里项目里的故障管理行为才真正可控。这也是我做完这一轮用例评审后最想提醒的一件事。
返回列表