ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Robot Framework循环读取Excel表格操作:接口自动化与数据驱动实战详解

Robot Framework循环读取Excel表格操作:接口自动化与数据驱动实战详解 在之前的接口自动化项目里我拿到过一张200多行的Excel用例表每一行都是一组账号、密码和期望返回码按老办法是手工从Excel复制参数到请求里跑完再手动对比结果光造数就占掉一下午。后来我把这套流程完全交给Robot Framework处理循环读取Excel表操作脚本自动拿每一行数据去请求接口再自动把响应状态、耗时和通过结果写回Excel。这篇文章就是把那次改造里的思路、代码和坑集中整理出来需要的可以直接抄。所谓的“robot framework循环读取excel表操作”本质要解决的不复杂把一张二维表变成Robot Framework能遍历的数据然后在循环里按行或者按单元格取值驱动后续的关键字执行。它适用于接口测试造数、批量数据初始化、RPA流程里的表格处理、甚至用Excel管理配置参数的场景。适合自动化测试工程师、RPA脚本开发以及所有被“Excel手工操作到吐”的同行参考。1. 先想清楚Excel在RF里的角色定位再聊循环怎么写很多新手拿到这个需求第一反应就是去找“循环”的关键字怎么写结果代码写出来能跑但一到数据量大、用例逻辑复杂就崩了。问题不在于循环语法而在于没把Excel在Robot Framework里到底充当什么角色想清楚。1.1 Excel不是“界面”它只是一份数据源在Robot Framework的世界里Excel文件不应该被当成一个需要反复打开的“软件窗口”而是应该被看作一个二维数据源。就像你从数据库查出来的一张结果集、一个Python列表本质上无非是多行多列的数组。这个思维转换很重要。一旦你接受了Excel是数据源自然就会明白三件事你要处理的是行和列不是“第几个Sheet”的视觉位置循环遍历时关注的维度是行号区间和列号区间真正要优化的不是循环本身而是怎么高效地把Excel里的内容取出来交给循环用。1.2 三种最常见的“循环Excel”业务模式根据我经手的项目所谓循环读取Excel刨到根上只有三种模式大部分需求都是它们的变体。模式A整表逐行处理这是最典型的用法。表头是字段名从第二行开始每行是一条数据循环里按行读取单元格然后去执行某个操作。比如读一列用户名、一列密码然后逐个调登录接口或者读一列手机号批量发优惠券。表格结构示例 username password expect_code test01 abc123 200 test02 abc123 400模式B读取配置单元格驱动整套流程有时候Excel里存的不是大批量数据而是一组参数。比如第一行第二列是环境地址第二行第二列是超时时间。这种情况不需要循环所有行只要一次性读取指定单元格赋值给变量再用变量去驱动执行。循环通常出现在“同一套配置要跑多轮”时。模式C边读边写跑完后回填结果执行完一批数据后需要把执行结果比如Pass/Fail、响应码、耗时写回Excel的指定列。这是最容易被忽略的一环也是实操中回报最高的能力。因为自动化测试不只是“看”还要“留痕”回填后的Excel可以直接反给业务方看比截图报告更有说服力。三种模式的对照如下模式常见场景核心操作整表逐行处理接口造数、批量提数、批量注册循环行号读取多列配置单元格驱动环境参数、变量配置读取固定坐标传参给关键字边读边写回填测试结果汇总、数据清洗执行后定位行号写入状态列1.3 动手写循环前必须先回答的三个问题这三个问题如果不先想清楚写出来的循环往往是“这段代码明明加了循环但没处理干净”。它们分别是第一数据读多少行可以从表头数固定读10行也可以动态获取总行数。动态获取要用Get Row Count但要注意空行和合并单元格都会影响行数统计后面第6章专门说这个坑。第二顺序是否敏感如果执行顺序无关紧要循环体里不需要记录行号但如果最后要把结果写回Excel的对应行就必须保留行号。这里要用IN ENUMERATE在循环时既拿到数据又拿到序号一举两得不必手动维护一个计数器。第三某一行数据处理失败时继续还是中断默认情况下RF在关键字报错时会中断当前测试用例。如果你希望“这一行报错了下一行接着跑”就得用Run Keyword And Continue On Failure或者TRY/EXCEPT包住可能出错的操作。这个决策直接决定你写不写异常处理。这三个问题回答完之后再去看循环语法就会清晰很多你选哪一列、从哪里开始、要不要行号、出错怎么处理全都有了依据。2. Excel库选型与环境搭建先避开老教程埋的雷Robot Framework本身不带操作Excel的库需要用第三方库。但这块的选型坑非常多尤其是当你搜索到大量旧教程时跟着做很可能第一步就失败。下面我直接给结论和理由。2.1 三个常用库到底怎么选目前社区里能用的方案主要有四个ExcelLibrary、ExcelRobot、DataDriver、以及绕道pandas。它们的核心差异如下库名底层依赖支持格式读写能力维护状态ExcelLibraryxlrd pywin32xls / xlsx读取写入依赖Windows COM读尚可写受限老牌多年未大更新ExcelRobotopenpyxlxlsxxls需先转换读写都行跨平台社区活跃纯Python实现DataDriver底层可配ExcelRobot等xlsx / csv等只读专为数据驱动测试设计pandas经Evaluate调用pandas openpyxlxlsx / csv等读写都行数据科学标配性能最强这里有个历史背景需要说明。早年的RF教程几乎都是ExcelLibrary它的读取依赖xlrd写入依赖pywin32。后来xlrd在2.0版本直接砍掉了对xlsx文件的支持只保留老的xls。结果就是大量老教程中的代码在新环境里一跑就报错Excel xlsx file not supported。如果你非要用ExcelLibrary要么把xlrd强制降到1.2.0要么只处理老格式的xls。但仍不推荐在写入场景用它因为写Excel在非Windows环境等于没法用。ExcelRobot则完全不同。它基于openpyxl读写都是纯Python操作跨平台对xlsx支持很好而且很多API命名刻意贴近ExcelLibrary老代码迁移成本低。如果你面向的表格都是xlsx重点用ExcelRobot就对了。2.2 我的选型建议按场景划分我的建议是读写并且在Windows以外的环境跑选ExcelRobot没有第二个更省心的选择。纯读取、数据量不大、只想跑个一次性脚本ExcelLibrary也能用但建议直接在当前环境确认xlrd版本别再为老库额外折腾。想用Excel驱动“一行数据就是一条测试用例”不要自己写循环直接用DataDriver它是专门的解决方案。表格非常巨大几千行以上绕道pandas。在RF里用Evaluate加载pandas一次把数据转成列表或字典速度秒杀逐格读取。说句大实话如果项目允许我个人的长期习惯是把Excel当中间输入能转CSV就转CSV性能会再上一个台阶。但为了保证通用性下面的例子仍以xlsx直接读取为主。2.3 安装和最小验证安装过程不复杂但要注意别在同一个环境里同时装了一堆互相冲突的Excel库。建议新建一个虚拟环境按需安装pip install robotframework pip install robotframework-excelrobot验证是否安装成功可以直接命令行跑Robot Framework自带的关键字查询或者用一条最小用例测试导入*** Settings *** Library ExcelRobot *** Test Cases *** Check Excel Library Import Log ExcelRobot imported successfully运行后不报“Library not found”说明环境OK。如果还要用RequestsLibrary调接口就再装pip install robotframework-requests安装完成后不用急着写循环先在命令行里确认库版本pip show robotframework-excelrobot python -c import openpyxl; print(openpyxl.__version__)顺便提一句如果你之前用过老教程的ExcelLibrary并且环境里已经有了xlrd安装完ExcelRobot后最好检查一下python -c import xlrd; print(xlrd.__version__)如果版本大于等于2.0而你又必须在老库方案里做xlsx读取那就降级pip install xlrd1.2.0不过我的建议是直接抛弃老库别在这上面浪费生命。3. 核心循环写法与维度逻辑两段式结构是基本功这一章我给你讲透循环读取的骨架。掌握了这个骨架不管你的Excel长什么样都能套进去。核心就一句话先一次性把Excel数据准备好再在内存里循环。我把所有读写操作分了两段既能保持代码清晰又能尽量减少循环内反复访问文件。3.1 RF的FOR循环基础语法先明确Robot Framework当前主流版本RF 4.x / 5.x / 6.x的循环语法。旧版本的:FOR写法已经废弃新写法如下FOR ${item} IN {items} Log ${item} END这是最基础的遍历列表。如果想把列表里的每一项拆开用或者需要同时拿到序号用这些变形# 带序号遍历index从0开始 FOR ${index} ${item} IN ENUMERATE {items} Log ${index} - ${item} END # 同时遍历多个列表按位置一一对应 FOR ${name} ${password} IN ZIP ${names} ${passwords} Log ${name}:${password} ENDIN ENUMERATE在Excel回写场景下特别有用因为回写需要知道当前是第几行。IN ZIP则适合那种“你把几列单独取出来想一次配对遍历”的场景省得在循环体里再去按索引取值。3.2 推荐写法先整表读入再逐行处理很多新手写循环时习惯在循环内部反复打开Excel文件# 不推荐的写法每一行都重新打开/关闭文件 FOR ${row} IN RANGE 2 10 Open Excel ${EXCEL_PATH} ${cell} Read Excel Cell ${row} 1 Close Excel END这段代码能运行但性能很差。因为Robot Framework每次Open Excel都会重新加载整个工作簿如果Excel里有几百行数据文件就得被反复解析几百次。正确的做法是把文件打开一次循环只负责读取单元格和业务操作*** Settings *** Library ExcelRobot *** Variables *** ${EXCEL_PATH} C:/data/accounts.xlsx *** Keywords *** Loop Read Accounts Open Excel ${EXCEL_PATH} ${rowCount} Get Row Count Log Total rows: ${rowCount} FOR ${row} IN RANGE 2 ${rowCount 1} ${username} Read Excel Cell ${row} 1 ${password} Read Excel Cell ${row} 2 Log Processing user: ${username} # 这里可以调用登录、下单、发券等关键字 END Close Excel这里有几个必须理解的细节为什么从2开始因为第1行是表头不是数据。为什么结束值是${rowCount 1}因为IN RANGE和Python的range一样是半开区间不包含末尾值。如果总行数是100你却写IN RANGE 2 100那么实际读取的是第2到第99行第100行被吃掉了。这是最容易犯的低级错误。Get Row Count返回的是Excel里被认为有数据的行数跟你肉眼看到的“行号”可能不完全一致尤其是存在格式化空白行时。这个细节在第6章展开。3.3 按列遍历和按单元格偏移遍历逐行读是最常见的但还有一种场景是“某一列是一组参数需要逐个取出来用”此时可以直接提取整列${columnValues} Read Excel Column 1 FOR ${value} IN {columnValues} Log Column value: ${value} ENDRead Excel Column返回的是一个列表可以直接丢给FOR IN遍历。这种方式在处理配置表中的“第一列是key第二列是value”这类结构时很舒服。如果一行数据要多列组合建议先读整行再用Collections库按索引拆${rowData} Read Excel Row 2 ${username} Get From List ${rowData} 0 ${password} Get From List ${rowData} 1这样比连续几次Read Excel Cell更省事尤其在列很多的情况下代码可读性会好很多。3.4 循环体里的变量作用域需要注意在RF 5之前FOR循环内部定义的变量在循环结束后仍然可以在外层访问RF 5之后把循环变量的作用域改成了“循环内局部”循环结束后变量会被清理外层访问不到。这个变更本身是为了防止变量污染但会坑到从旧项目迁移过来的脚本。我的习惯是如果循环外部需要用到循环内最后一次计算的结果就在循环之前声明一个默认变量循环内显式给它赋值而不是直接依赖循环变量。这样不管RF版本如何变化脚本行为都一致。${lastResult} Set Variable NONE FOR ${row} IN RANGE 2 ${rowCount 1} ${lastResult} Read Excel Cell ${row} 3 END Log ${lastResult}4. 实测案例用Excel驱动登录接口测试并回写结果理论说再多不如跑一遍完整案例。这一章我以一个非常常见的“Excel驱动登录接口测试”为例覆盖读取、请求、断言、回写四个环节。这个案例我实际在项目里跑过可以直接改改路径和接口地址就复现。4.1 需求场景和Excel模板设计假设需求是这样Excel里有100条账号数据每条数据包含用户名、密码、期望HTTP状态码。脚本需要逐个调用登录接口把实际返回码、响应消息、耗时写回同一行的对应列最后把整张表保存。Excel模板设计如下第1行是表头第2行起是数据A第1列B第2列C第3列D第4列E第5列F第6列usernamepasswordexpect_codeactual_coderesultcost_time(s)test01abc123200test02abc123400D列是实际状态码E列是PASS/FAILF列是耗费的秒数。初始状态这3列都是空的跑完脚本自动填好。4.2 完整用例代码我用的库是RequestsLibrary底层requests库发HTTP请求ExcelRobot操作Excel。完整脚本*** Settings *** Library ExcelRobot Library Collections Library RequestsLibrary *** Variables *** ${EXCEL_FILE} C:/data/login_cases.xlsx ${LOGIN_URL} http://demo.internal/api/login *** Keywords *** Clear Result Columns [Documentation] 每次执行前清空结果列避免历史数据导致误判 Open Excel ${EXCEL_FILE} ${rowCount} Get Row Count FOR ${row} IN RANGE 2 ${rowCount 1} Write Excel Cell ${row} 4 ${EMPTY} Write Excel Cell ${row} 5 ${EMPTY} Write Excel Cell ${row} 6 ${EMPTY} END Save Excel Close Excel Login By Row [Arguments] ${row} ${username} Read Excel Cell ${row} 1 ${password} Read Excel Cell ${row} 2 ${expect_code} Read Excel Cell ${row} 3 ${payload} Catenate {username: ${username}, password: ${password}} ${resp} POST ${LOGIN_URL} json${payload} ${actual_code} Set Variable ${resp.status_code} ${cost_time} Evaluate round(${resp.elapsed.total_seconds()}, 3) Write Excel Cell ${row} 4 ${actual_code} IF ${actual_code} ${expect_code} Write Excel Cell ${row} 5 PASS ELSE Write Excel Cell ${row} 5 FAIL END Write Excel Cell ${row} 6 ${cost_time} *** Test Cases *** Loop Login And Write Back Clear Result Columns Open Excel ${EXCEL_FILE} ${rowCount} Get Row Count FOR ${row} IN RANGE 2 ${rowCount 1} Run Keyword And Continue On Failure Login By Row ${row} END Save Excel Close Excel4.3 关键设计思路为什么这样做为什么先Clear Result Columns因为Excel文件往往会被反复执行多次。如果不先清空D、E、F列第二次执行时如果某行请求异常导致没有写入看到的就是上一次运行留下的旧结果极容易干扰判断。先清空等于给每次执行一个干净的起跑线。为什么把请求逻辑抽成Login By Row关键字因为主循环里只需要一行Run Keyword And Continue On Failure Login By Row ${row}如果某一行因为数据问题抛异常循环不会中断。这是自动化脚本能不能通宵跑的关键否则第10行出错后面90行全都不执行了。为什么用Run Keyword And Continue On Failure而不是TRY/EXCEPT两者都可以但Run Keyword And Continue On Failure更简洁适合“失败那行跳过即可、无需特殊处理”的场景。如果你还希望在失败时把异常信息写回Excel那就用TRY/EXCEPT在EXCEPT分支里读取错误消息再回填FOR ${row} IN RANGE 2 ${rowCount 1} TRY Login By Row ${row} EXCEPT AS ${err} Write Excel Cell ${row} 5 ERROR Write Excel Cell ${row} 6 ${err.message} END END为什么用Write Excel Cell而不是Put Number To Cell因为ExcelRobot的Write Excel Cell可以覆盖字符串和数字类型行为稳定老库的Put Number To Cell在Windows依赖COM对象非Windows环境没法用。既然已经在ExcelRobot方案里了统一用Write Excel Cell少记一套API。4.4 请求参数里的JSON转义很多人栽在这里上面的Catenate拼接JSON字符串遇到用户名或密码里带引号、反斜杠时会产生非法JSON。更稳妥的方式是用Evaluate配合Python的json.dumps${payload} Evaluate json.dumps({username: ${username}, password: ${password}}) json这样拼出来的JSON一定是合法的不需要手工考虑转义。千万记住在接口测试字段值里出现特殊字符是常态别在“拼JSON”这个环节省事。4.5 返回值RequestsLibrary的POST关键字返回什么POST关键字返回的是一个requests.Response对象。你可以直接访问它的.status_code拿到状态码访问.elapsed拿到耗时timedelta.text拿到响应体文本。上面的代码里用Evaluate round(${resp.elapsed.total_seconds()}, 3)计算耗时注意${resp.elapsed.total_seconds()}在RF里会被先解析成浮点数再交给round处理所以这样写没问题。如果要在日志里打印响应体辅助排查加一行Log ${resp.text}跑完之后打开Excel文件D、E、F列已经全部回填了。5. 大数据量Excel的性能问题与优化方案很多人用“循环读取Excel”跑一两次没感觉以为这就结束了。等你拿一张几千行的Excel去跑就会明显感到速度不对劲。这一章我把性能问题的根子和优化方案一次性说清。5.1 慢的根本原因文件重复加载如果你用ExcelRobot的Read Excel Cell在循环里一行一行地读即使文件只Open Excel了一次底层openpyxl在工作簿加载后不会每次重新解码整个文件所以“只需要打开一次文件”是成立的。真正影响性能的通常是每次读取cell都有函数调用和类型转换开销几千行乘几列这个开销被放大。而如果用的是老库且循环里每次都Open Excel那就是灾难级缓慢——每次Open都要完整解析一次文件。从实际经验看一次打开文件的方案处理500行以内的数据没什么感觉到几千行就比较明显。以下是几个有效的优化方向。5.2 优化方案一一次读入为内存列表再遍历不要循环里一个个Read Excel Cell先把整张表一次性读入内存。如果你用pandas可以在Setting里不增加库直接通过Evaluate加载*** Test Cases *** Fast Loop With Pandas ${rows} Evaluate pd.read_excel(r${EXCEL_FILE}).values.tolist() pandas as pd Log Total data rows: ${rows.__len__()} FOR ${row} IN {rows} ${username} Get From List ${row} 0 ${password} Get From List ${row} 1 # 业务处理 END.values.tolist()会把每一行变成一个Python列表整个Excel变成“列表的列表”Robot Framework的FOR IN可以直接遍历。这种方式在1000行以内感受最明显速度能快一到两个数量级。但要注意pandas读取时会把空单元格变成NaN日期变成Timestamp后续处理要自行转类型这是性能换来的数据代价。如果你不想引入pandas也可以用Read Excel Row按行号读放进一个大列表里再遍历{allRows} Create List Open Excel ${EXCEL_FILE} ${rowCount} Get Row Count FOR ${row} IN RANGE 2 ${rowCount 1} ${rowData} Read Excel Row ${row} Append To List ${allRows} ${rowData} END Close Excel FOR ${rowData} IN {allRows} ${username} Get From List ${rowData} 0 ${password} Get From List ${rowData} 1 # 业务处理 END这种方式虽然比pandas慢但不用引入额外依赖代码风格也更接近RF原生。5.3 优化方案二用DataDriver把每行变成一条测试用例如果“每一行Excel数据”本质上就是“一条测试用例”那么用DataDriver是最优雅的。它不依赖你手写FOR循环而是让Robot Framework把Excel的每一行自动展开成一条独立测试用例报告里还能看到每一行的执行结果。配置方式*** Settings *** Library DataDriver C:/data/login_cases.xlsx sheet_nameSheet1 Test Template Login With Data *** Test Cases *** Login With ${username} and ${password} [Template] Login With Data ${username} ${password} *** Keywords *** Login With Data [Arguments] ${username} ${password} # 这里写请求和断言DataDriver要求表头列名与模板参数名对应并且会为Excel里的每一行生成一条“Login With test01 and abc123”这样的测试用例。好处是执行粒度细没跑过的用例在报告里显示为失败不会因为一条数据挂了而吞掉整个循环执行记录。循环方式像是“框架帮你把Excel‘摊开’了”代码量也最少。5.4 优化方案三把xlsx预处理成CSV再读如果你只是要读取数据做计算不关心写回Excel那么xlsx其实是不划算的中间格式。xlsx本质是一个zip压缩包解析它的开销远大于读纯文本的CSV。你可以先用Excel/WPS把表另存为CSV或者用LibreOffice命令行批量转换soffice --headless --convert-to csv C:/data/login_cases.xlsx然后在Robot Framework里可以自己用Evaluate读CSV${rows} Evaluate [line.strip().split(,) for line in open(rC:/data/login_cases.csv, encodingutf-8)]这种方式读取速度极快但缺点是要多一步预处理而且CSV不支持多个Sheet。适合数据量大、只需要单表信息、且不需要回写Excel的场景。5.5 多进程并行执行Robot Framework本身是单进程执行的单个测试套件内无法真正并发跑循环。想提速可以考虑把Excel按行拆成多个文件用pabot并行执行多个套件。这个方案适合测试用例执行耗时占比远大于读取耗时的场景。如果你的瓶颈在请求等待时间上pabot可以把总耗时压缩到你想象不到的程度。不过并行后回写Excel就要格外小心两个进程同时写同一个文件必炸解决办法是每个进程写各自的文件最后再合并。6. 循环读取Excel时最容易踩的坑这一章是我个人最有价值的部分。直接按“现象、原因、处理”三段式列表给出来每一条都是从真实项目里踩出来的不是文档翻译。6.1 xlrd 2.0不支持xlsx老教程全是雷如果你跟着某篇2019年的博客用Open Excel环境里装的是新版xlrd第一行就会报Excel xlsx file not supported。原因是xlrd从2.0开始砍断了xlsx支持只保留老格式xls。处理方案两条路降级pip install xlrd1.2.0换库直接用ExcelRobot基于openpyxl治标又治本。我的建议是直接换库。老库本身不更新了为了一个xlsx读取把核心依赖锁死在旧版本后续早晚要还债。6.2 合并单元格读出来只有左上角有值其它全是NoneExcel里如果A2:A3合并了在openpyxl的模型里只有A2存了值A3是空值。循环读取时A3返回的可能不是“空字符串”而是Python的None。如果你直接拿这个值去接口请求requests会把None拼进JSON里服务端很容易报参数类型错误。处理方式要么在Excel交付源数据时强制“不要合并单元格”要么在读取后统一判断None。复制一个关键字来处理空值*** Keywords *** Get Safe Cell Value [Arguments] ${row} ${column} ${value} Read Excel Cell ${row} ${column} ${value} Evaluate ( if ${value} is None else ${value}) [Return] ${value}这样就能把None统一转成空字符串后续处理逻辑简单很多。6.3 公式单元格取不到计算结果如果Excel的某个单元格是B2*C2这种公式openpyxl直接读取时通常拿不到计算后的值而是拿到公式字符串或者返回None。这跟你用Excel软件打开看到的现象完全不同很容易让人怀疑是不是Excel文件坏了。想让openpyxl读取到公式计算后的结果要求条件比较苛刻文件必须被Excel或WPS等桌面软件打开并保存过一次留下计算缓存这样才能用data_onlyTrue的方式读到值。在RF层面ExcelRobot对公式单元格的读取在不同版本下表现不一致稳妥做法是要求提供数据的人把公式结果粘贴成纯数值或者你自己在脚本里用openpyxl的load_workbook(data_onlyTrue)去读。对自动化测试而言最省心的还是让数据提供方直接给纯数值版本的Excel。6.4 空行和None值导致的行数统计不准Get Row Count返回的是Sheet中“有内容的行数”不是“最后一行的行号”。如果Excel里第5行到第10行有数据但第11行曾经格式化过边框、设置了背景色Get Row Count可能反映不一致。更常见的是表尾有几个“看着是空行、实际上有隐藏字符”的行循环时会多跑几遍。处理方法是循环前先打印行数Log rowCount is ${rowCount}如果发现行数偏多就在循环里加一个判断当前行单元格内容为空就跳过。${check} Read Excel Cell ${row} 1 Continue For Loop If ${check} ${EMPTY} or ${check} NoneContinue For Loop If是RF内置关键字跳过单次循环不影响后续行。这一招在脏数据Excel里非常常用。6.5 文件被Excel进程占用导致PermissionError如果你的Excel文件正被Excel软件打开Robot Framework脚本去Save Excel大概率会报PermissionError。这是操作系统的文件锁机制不是RF或库能绕开的。遇到这个问题时我一般直接用Python的copy模块复制一份临时文件来操作${tmpFile} Evaluate __import__(shutil).copy(r${EXCEL_FILE}, rC:/temp/xxx_copy.xlsx)脚本对临时文件读、改、存最后再整体替换原始文件。虽然多了一步拷贝但至少不会因为Excel没关而中断。更正规的做法是流程上强制要求执行前关闭Excel或者让脚本有单独的产物目录不直接动源文件。6.6 日期被读成datetime对象或一串数字Excel里的日期底层实际上是浮点数从1900年1月0日起算的天数。openpyxl读出来时可能返回datetime对象也可能返回一个数字取决于单元格格式。在RF里处理起来非常疼因为你拿到的值类型可能不固定。最省心的规避方式要求Excel模板里所有日期列都设置成“文本”格式让数据提供方按字符串录入。如果你拿到的已经是日期类型可以在循环里做一次格式化${dateStr} Evaluate $value.strftime(%Y-%m-%d) if hasattr($value, strftime) else str($value)6.7 路径分隔符、变量作用域这些看起来小但真烦的问题在Windows环境RF里使用文件路径时反斜杠会被当作转义字符C:\data\file.xlsx经常解析错。最简单的处理是用正斜杠C:/data/file.xlsx或者写成双反斜杠C:\\data\\file.xlsx。我在实践里一律用正斜杠少踩一个坑。变量作用域的问题在第3章提过。RF 5之后循环内局部变量在循环结束后不能再访问。如果你把${rowCount}之类的变量定义在循环外没问题但如果试图在END之后访问循环里的${username}在RF 5及以上会报变量不存在。所以大型关键字里尽量显式声明外部变量。最后再分享一个小习惯我在真实项目里从来不直接依赖某一种Excel读取API走到底。需要快速出结果时优先整体读入内存再遍历需要逐条可追踪时用DataDriver需要回写报表时用ExcelRobot把保存操作放在一个Suite Teardown里统一执行。这样循环读取Excel这套组合拳不管遇到什么表格都能接得住。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进