ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

汽车电子测试:Robot Framework 与 CAN/UDS 诊断自动化

汽车电子测试:Robot Framework 与 CAN/UDS 诊断自动化 汽车电子测试这个圈子最近两年有个明显的变化越来越多的团队不再从零手搓测试脚本也不再抱着几个笨重的商业测试软件不放而是转向了一套开源的、关键字驱动的自动化测试框架——Robot Framework。我做车载控制器测试前后也有不少年头从最早的串口手工发报文、到后来用各种脚本东拼西凑再到把整套回归测试搬进Robot Framework踩过的坑足够写满一个笔记本。这篇就把我理解的Robot Framework是什么、它凭什么在汽车电子测试里站住脚、以及从环境搭建到CAN/UDS诊断封装落地的全过程聊透顺带把那些只有实际跑过一遍才会知道的细节摊开。不管你是刚开始接触ECU测试的新人还是想给现有测试流程做自动化改造的老手应该都能从这里抄到可以直接用的东西。1. 为什么汽车电子测试圈在往Robot Framework上靠1.1 先搞清楚汽车电子测试到底在测什么聊框架之前得先把测试对象说明白不然后面全是空中楼阁。汽车电子测试的核心对象是ECU也就是电子控制单元车上的发动机、变速箱、车身、电池管理、网关每一个都是一个甚至多个ECU在跑。测试的内容大致分几块一是通信层CAN、CAN FD、LIN这些总线上的报文收没收到、周期对不对、信号值合不合理二是诊断层也就是基于UDS协议的诊断服务读故障码、清故障码、读数据流、刷写升级三是功能层比如车门锁控制、座椅调节、灯光逻辑这些应用行为四是网络管理休眠唤醒、网络超时这些和整车功耗强相关的行为。这些测试有个共同特点绝大部分动作都是发一个激励、等一个响应、断言响应符合预期。听起来简单但真做起来一条测试用例里可能夹着几十条报文收发、几百毫秒的时序等待、好几个信号的联合判断。如果用纯脚本写代码很快就会变成一团谁也看不懂的意大利面。这就是为什么测试框架的选择如此重要——它决定了你的测试资产是一堆一次性的脚本还是能长期维护、能复用、能交给别人接着做的资产。汽车电子测试还有几个绕不开的现实约束硬件在环台架资源贵、ECU样件数量有限、测试窗口经常被开发进度挤压。这就要求测试脚本必须写得快、改得快、跑得稳而Robot Framework在设计上恰好就是冲着这些痛点去的。1.2 关键字驱动的思路为什么和汽车测试这么合拍Robot Framework最核心的设计是关键字驱动。简单说它把每一个测试动作都抽象成一个关键字测试用例就是用这些关键字拼出来的自然语言句子。比如连接CAN通道、发送诊断请求、校验故障码已置位这些读起来就像人话的句子就是一条条关键字调用。这背后其实是一种分层的思想底层是真正干活的Python代码负责和硬件、和DLL、和CAN卡打交道上层是关键字把底层能力包装成人能看懂的业务语言最上面是用例只描述测什么不关心怎么测。这个分层对汽车电子测试来说价值极大。原因很直接汽车测试的底层通信细节极其繁琐CAN报文的打包、字节序的处理、诊断服务里长度字节和子功能的拼装、ISO-TP的分帧重组这些东西写起来又枯燥又容易错。如果不分层每个做测试的人都要重复理解一遍这些细节。分层之后通信细节只在一处实现所有人共享同一套关键字新人上手时不用管底层直接写读取故障码就行。另一个好处是测试用例的可读性。整车厂和供应商之间经常要交换测试规范一份写满发送ID为0x7DF、数据为02 10 03的脚本业务方看不懂而一份写满进入扩展会话、读取故障码的Robot Framework用例连产品经理都能大致判断测了什么。这在测试评审、用例复用、跨团队协作时省下的沟通成本是实打实的。1.3 和几种常见方案摆在一起比一比光说好话不客观得把Robot Framework和汽车测试圈常见的其他方案摆一起对比你才知道它适合什么、不适合什么。方案优势短板适合场景Robot Framework关键字驱动、报告详细、Python生态、开源免费大规模并发性能一般、学习曲线在封装层功能测试、诊断测试、回归测试、HIL集成手写Python脚本灵活、无框架约束难维护、无统一报告、复用差一次性验证、临时调试商业测试软件图形化、厂商支持、硬件配套好授权贵、灵活度受限、迁移成本高产线测试、标准化交付LabVIEW等图形化硬件接口丰富、工程师熟悉版本管理难、代码复用差台架搭建、快速原型Robot Framework的定位很清晰它适合做需要长期维护、需要团队协作、需要清晰报告的自动化测试。它不追求极致的执行速度也不是图形化的傻瓜工具但在把测试资产沉淀下来这件事上它的性价比几乎没有对手。理解这一点很重要因为如果你只是要临时验一条报文说实话一个二十行的Python脚本可能更快。2. 从零搭好一套能跑汽车电子测试的环境2.1 Python和Robot Framework的安装与版本选择Robot Framework本身是Python写的所以第一步是装Python。我一般建议直接用Python 3.8到3.11之间的版本。为什么不推荐最新的因为汽车测试要用的那几个关键库比如python-can、udsoncan这些对Python新版本的适配有时会滞后装最新版反而容易在依赖上卡住。我自己目前稳定用的是Python 3.10几年下来没出过什么幺蛾子。装完Python之后Robot Framework本体一条命令就能装上pip install robotframework装完验证一下版本robot --version能打印出版本号就说明本体没问题了。这里有个细节值得说如果你要同时维护多个项目强烈建议用虚拟环境也就是venv。因为不同项目可能依赖不同版本的库混在一个全局环境里迟早打架。python -m venv venv # Windows下激活 venv\Scripts\activate # Linux或Mac下激活 source venv/bin/activate激活之后再装Robot Framework和其他库这样每个项目的依赖是隔离的迁移到别人机器上只要导出依赖清单就能复现这在团队协作里非常关键。2.2 汽车电子测试绕不开的几个Python库光有Robot Framework本体还测不了汽车电子它需要下面这些库来和CAN总线、诊断服务打交道。python-can这是CAN通信的基石支持各种CAN卡硬件从便宜的USB转CAN到Vector、Kvaser这些专业设备都能接。cantools负责解析DBC文件有了它你就能用信号名而不是原始字节来读写报文可读性天差地别。udsoncan专门实现UDS诊断协议的高层库处理会话切换、安全访问、故障码读写这些标准服务。can-isotpUDS的传输层依赖负责把超过8字节的诊断数据分帧和重组udsoncan会用到它。一条命令把它们都装上pip install python-can cantools udsoncan can-isotp需要提醒的是这些库之间是有版本依赖关系的udsoncan对can-isotp的版本有要求。如果你装完发现导入报错多半是版本没对上可以针对性地指定版本安装比如pip install can-isotp1.5。这种依赖冲突在汽车测试环境里挺常见后面常见问题部分我会专门聊怎么排查。2.3 工程目录怎么组织才不后悔环境装完接下来是目录结构。这一步很多人随便建建就开工结果项目做大了返工重排痛苦得很。我给一套自己用了很久、经得起项目规模增长的结构project/ ├── venv/ ├── resources/ │ ├── can_keywords.robot # CAN通信相关关键字 │ ├── uds_keywords.robot # 诊断相关关键字 │ └── common_variables.robot # 公共变量 ├── libs/ │ ├── canalibrary.py # 自定义CAN库 │ └── udslibrary.py # 自定义诊断库 ├── testdata/ │ └── vehicle.dbc # DBC文件 ├── testsuites/ │ ├── smoke/ │ │ └── ecu_basic.robot │ └── regression/ │ └── dtc_test.robot └── output/这个结构的核心思想是把能力resources和libs、数据testdata、用例testsuites分开。能力层被多个用例共享改一次全生效数据层和用例解耦换一个DBC就能测另一个车型用例层只写业务。我自己最深的体会是把资源文件和自定义库单独放目录后期换硬件、换DBC、换诊断库的时候改动范围能控制在最小。汽车项目周期长、需求变更频繁这种隔离的价值会在项目后期集中体现出来。3. 核心用法拆解把CAN报文和诊断封装成关键字3.1 三段式语法先跑通一个最小用例Robot Framework的用例文件主要分几个区段最常用的是Settings、Variables、Test Cases和Keywords。先看一个最小可跑的例子*** Settings *** Library can_keywords.py *** Test Cases *** 验证ECU上电后能正常响应诊断 [Tags] smoke 打开CAN通道 channel0 bitrate500000 进入扩展会话 读取ECU版本信息 [Teardown] 关闭CAN通道这段用例里打开CAN通道、进入扩展会话、读取ECU版本信息都是关键字它们具体怎么做藏在关键字定义或者Python库里。用例本身只描述流程读起来是不是像一份测试规范这就是关键字驱动的魅力。段落的区分靠*** Settings ***这样的标记区段内用表格或空格对齐即可格式上比想象中宽松但缩进和分隔符要一致不然解析会报错。3.2 变量和资源文件管好公共东西汽车测试里会有一大堆公共的东西CAN通道号、波特率、诊断请求ID、诊断响应ID、DBC文件路径、各种超时时间。这些如果写死在每条用例里改起来就是灾难。正确做法是抽到变量文件里。*** Variables *** ${CHANNEL} 0 ${BITRATE} 500000 ${REQ_ID} 0x7DF ${RESP_ID} 0x7E8 ${DBC_FILE} ${CURDIR}/../testdata/vehicle.dbc ${TIMEOUT} 2s然后在资源文件里引用这些变量用例文件再导入资源文件。这样从classic CAN换到CAN FD、从500k换到2M只需要改变量用例一个字不用动。变量作用域也值得注意在Variables区定义的全局可用在用例里用Set Variable定义的只在当前用例有效跨用例传值要用Set Suite Variable或Set Global Variable。我见过不少新手在这里栽跟头明明变量设了却读不到八成是把局部变量当全局用了。3.3 自定义Python库才是真正的重头戏Robot Framework自带的能力有限真正的活儿要靠自定义Python库来干。下面这个例子演示怎么封装一个CAN通信库把python-can的操作包起来# canalibrary.py import can class CanLibrary: def __init__(self): self.bus None def open_can_channel(self, channel0, bitrate500000): self.bus can.Bus( interfacesocketcan, channelchannel, bitratebitrate ) def send_message(self, arbitration_id, data): msg can.Message( arbitration_idint(arbitration_id, 16) if isinstance(arbitration_id, str) else arbitration_id, datadata, is_extended_idFalse ) self.bus.send(msg) def receive_message(self, expected_id, timeout2.0): deadline time.time() timeout while time.time() deadline: msg self.bus.recv(timeout0.1) if msg and msg.arbitration_id expected_id: return msg.data raise AssertionError(f超时未收到ID为{hex(expected_id)}的报文) def close_can_channel(self): if self.bus: self.bus.shutdown()有了这个库Robot Framework里就能直接用Open Can Channel、Send Message这些关键字。注意方法名下划线会自动转成关键字的空格形式open_can_channel对应Open Can Channel。这是Robot Framework的命名约定很多人第一次看不明白关键字怎么会自动出现就是没吃透这一点。3.4 断言和报告别小看这块测试用例没有断言就是耍流氓。Robot Framework内置了Should Be Equal、Should Contain、Should Be True这些断言关键字直接在用例里用*** Test Cases *** 读取故障码数量正确 进入扩展会话 读取故障码 ${count} 获取故障码数量 Should Be True ${count} 0执行完之后Robot Framework会自动生成HTML格式的日志和报告这是它的一大亮点。每条用例的执行详情、每一步的输入输出、耗时、截图如果涉及都能看到失败时还会高亮错误位置。整车厂做测试评审的时候直接甩一份报告就能说明问题比你自己写Word文档靠谱得多。报告默认生成在output.xml、log.html、report.html三个文件里用浏览器打开report.html看总体结果用log.html看细节。4. 典型汽车电子测试场景怎么落地4.1 ECU上下电与网络管理测试网络管理测试是汽车电子的高频场景核心是验证ECU能不能正常休眠、能不能被正确唤醒、休眠电流是否达标。这类测试对时序要求高人工操作很难保证一致性正是自动化的用武之地。思路是用可编程电源控制ECU的供电在Robot Framework里封装一个电源控制关键字然后组合CAN通信做判断。典型流程是先让总线进入正常通信状态然后发网络管理报文请求休眠等待一段时间后用CAN分析仪观察总线上是否还有报文如果一段时间内静默说明休眠成功。用例大概长这样*** Test Cases *** ECU正常进入休眠 [Tags] network_management 上电ECU 等待网络通信正常 timeout5s 发送网络管理报文 0x400 02 00 00 等待总线静默 timeout5s ${has_traffic} 监测总线活动 duration3s Should Be Equal ${has_traffic} ${False} [Teardown] 断电ECU这里等待总线静默和监测总线活动是需要自己封装的因为标准库没有现成的。封装的难点在于总线静默的判断要有容差不能一有报文就断言失败得考虑偶发的诊断报文或路由报文。我一般会给一个可配置的窗口比如3秒内如果收到的非网络管理报文少于某个阈值就认定接近静默。4.2 故障码DTC读写测试故障码测试是诊断测试的重头戏也是UDS应用最密集的地方。典型流程是制造一个故障条件比如断开某个传感器、给一个超范围的信号然后读故障码确认置位清除故障码确认能清掉再读确认清干净。这一串动作手工做极其繁琐自动化用Robot Framework配udsoncan分分钟搞定。用udsoncan封装一个诊断库把会话切换、安全访问、读DTC这些封装成关键字# udslibrary.py import udsoncan from udsoncan.connections import PythonIsoTpConnection from udsoncan.client import Client import isotp class UdsLibrary: def __init__(self): self.conn None self.client None def connect_uds(self, channel, req_id, resp_id): params { stmin: 32, blocksize: 8, wftmax: 0, tx_padding: 0x00, rx_flowcontrol_timeout: 1000, rx_consecutive_frame_timeout: 1000 } self.conn PythonIsoTpConnection( isotp.socket(), params ) self.client Client(self.conn, request_timeout2) self.client.open() def read_dtc(self): response self.client.read_dtc_information( udsoncan.services.ReadDTCInformation. Subfunction.reportDTCByStatusMask, status_mask0xFF ) return response.service_data.dtcs用例写起来就清爽了*** Test Cases *** 制造故障后DTC应正确置位 连接UDS 0 0x7E0 0x7E8 进入扩展会话 触发传感器故障 ${dtcs} 读取故障码 Should Contain ${dtcs} P0101 清除故障码 ${dtcs} 读取故障码 Should Not Contain ${dtcs} P0101配置参数那段的stmin、blocksize这些是ISO-TP传输层的流控参数stmin是分帧最小间隔blocksize是每多少帧等一次流控。这两个值设不对超过8字节的诊断响应就收不全这是新手最容易踩的坑之一。4.3 报文周期与信号一致性校验这条测试的目的很简单验证ECU发出的报文周期是不是符合设计信号值是不是在合理范围内。工具层面用python-can收一段时间报文把时间戳记下来算周期。周期校验的关键是容差计算。比如设计周期是100毫秒实际不可能精确到100毫秒一般允许正负10%的抖动也就是90到110毫秒。如果整车厂规范更严可能是正负5%。校验逻辑是把相邻两帧的时间戳相减超过容差就记一次异常最后统计异常比例。我一般不允许单次超差就判失败而是统计超差次数和比例因为总线上偶发的仲裁延迟很正常单次超差说明不了问题。*** Test Cases *** 整车报文周期在容差范围内 打开CAN通道 开始录制报文 duration10s ${周期异常比例} 校验报文周期 0x123 100ms 0.1 Should Be True ${周期异常比例} 0.01这里的0.01就是1%的异常率阈值0.1是正负10%的容差。这套逻辑封装好之后测几十上百条报文就是一串关键字的事比人工用示波器一帧帧看效率高太多。4.4 回归测试怎么组织才跑得动项目做大了用例几百上千条回归测试的组织就成了新问题。Robot Framework用目录和标签来组织testsuites下按模块分子目录每条用例打上smoke、regression、diagnostic这样的标签跑的时候可以按标签筛# 只跑冒烟 robot --include smoke testsuites/ # 跑全部回归 robot --include regression testsuites/ # 排除慢用例 robot --exclude slow testsuites/标签策略我建议至少分两层一层按测试类型smoke/regression/nightly一层按功能模块body/powertrain/network。这样既能快速冒烟也能按模块回归。另外长时间回归建议开启--outputdir指定输出目录避免几次运行的报告互相覆盖历史结果要保留方便对比前后版本的测试结论。5. 常见问题与排查技巧实录5.1 环境和依赖问题汽车测试环境最容易出问题的地方就是依赖。我整理了一张速查表现象可能原因解决办法导入udsoncan报错can-isotp版本不匹配按官方推荐版本固定安装robot命令找不到没激活虚拟环境激活venv或检查PATH库导入失败库文件名和类名不一致类名与文件名一致或显式指定中文乱码编码不是UTF-8文件存为UTF-8报告加编码参数关于库导入有个坑是自定义库的文件名和类名。Robot Framework导入Python库时默认找同名类如果canlibrary.py里的类叫CanLibrary没问题下划线转驼峰它能认但如果叫别的名字就得用Library canalibrary.py CanLibrary显式指定否则会报找不到库。这个问题我当年排查了半天才反应过来。5.2 通信类问题通信问题更隐蔽往往表现为偶尔失败。常见的有这几类第一类是总线负载过高导致报文丢失。当总线上报文密集、负载率超过70%时优先级低的报文可能被推迟甚至丢帧测试就会偶发失败。排查办法是把总线负载也记录下来如果失败用例都集中在高负载时段那基本就是它了。第二类是时序不稳。汽车ECU的响应时间受温度、电压、软件状态影响同样一条诊断请求冷启动和热机状态下的响应时间可能差很多。这时候超时时间不能卡太死得留足余量。我的经验是超时至少设为规范上限的1.5倍。第三类是波特率不一致。CAN卡的波特率和ECU不一致时会出现大量错误帧甚至完全收不到报文。这个用CAN分析工具一看错误帧计数就知道。这里要提一句采样点和波特率的匹配也影响通信稳定性有时候波特率数值对了但采样点偏了一样会出问题专业CAN卡都支持配置采样点一般设到75%到80%。5.3 用例设计与维护问题用例越写越多之后维护成本会慢慢显现。几条踩坑经验分享给你。一是别把太多逻辑塞进一条用例。一条用例超过二三十步就该考虑拆分了不然失败时根本定位不到是哪一步的问题。Robot Framework每一步都有日志但步骤太多日志翻起来也累。二是Setup和Teardown要用好。每条涉及硬件操作的用例都应该有Teardown保证异常退出时也能把CAN通道关掉、把ECU断电否则下一条用例可能因为资源没释放而失败。我吃过这个亏一条用例中途崩了没关通道后面一连串用例全挂排查半天才发现是资源泄漏。三是关键字要不断抽象。刚开始写的时候底层细节散在用例里很正常但随着场景增多你会发现很多步骤是重复的这时候就该把它们抽成更高层的关键字。比如给ECU上电并等待通信正常这种组合动作封装一次就能复用几十次。抽象的时机感很重要太早抽象会过度设计太晚抽象则积重难返我的判断标准是同一个动作被用了三次以上就该封。四是版本管理。.robot文件本质是文本用Git管起来毫无压力。我建议用例和DBC、库文件一起入库每次改动用分支跑通回归再合并。汽车项目周期动辄一两年没有版本管理几个月后你自己都不记得为什么那么写。6. 把这些串起来我的实际体会整套流程跑下来我的感受是Robot Framework在汽车电子测试里的价值不在于它本身多先进而在于它把通信细节和测试逻辑这两件本该分开的事真正分开了。底层Python库负责和硬件死磕关键字层负责把能力翻译成人话用例层负责表达测试意图。这种分层带来的复用性和可维护性在项目做到半年以上时会体现得淋漓尽致——改一个库几百条用例跟着受益换一个车型只改DBC和变量。几个我觉得特别实用的经验再强调一下。环境一定要用虚拟环境并固定依赖版本别让在我机器上能跑成为团队口头禅。自定义库要优先封装那些最繁琐、最容易出错的底层操作比如ISO-TP分帧、诊断响应解析把这些封死上层就轻松了。超时和容差这类参数不要拍脑袋定要根据规范和实测数据留足余量汽车测试最怕的就是偶发失败因为它会摧毁团队对自动化的信任。还有个细节报告和日志要认真对待。很多团队只关心用例过没过忽略了执行报告里藏着的大量信息。响应时间、报文数量、异常分布这些数据积累下来本身就是宝贵的测试资产能帮助判断软件质量趋势。我习惯定期把回归报告归档几个月后回头对比往往能提前发现一些缓慢劣化的迹象。这套东西搭起来不难难的是坚持把它用好用透而一旦用顺手你会发现汽车电子测试原来可以这么井井有条。
返回列表