资讯动态

Excel+Robot Framework:接口自动化测试的数据驱动实践

发布时间:2026/10/21 19:31:01 来源:尧图企业网站定制
做接口测试这些年我见过太多自动化项目死在“维护”这两个字上。脚本写的时候雄心勃勃跑起来也像模像样但业务一变动、参数一调整、接口一升级原本能稳定执行的用例开始集体“失灵”最后变成谁也不敢改、谁也不想碰的遗留物只能推倒重来。后来我换了个思路把用例从代码里解放出来用Excel管理场景和数据用Robot Framework只负责执行和断言。这套“Excel Robot Framework”的组合看起来不够炫却在落地效率、协作成本和长期维护性上实打实地解决了我前面说的那些问题。这个方案特别适合三类人一是团队里有人会写自动化脚本、但不想整天陪业务改代码的测试开发二是业务测试人员能看懂Excel、想参与用例维护但不想学编程三是项目接口数量中等、接口变动频繁需要快速跟上迭代节奏的团队。下面我会把环境搭建、用例模板设计、读取驱动、断言回写、常见坑排查这一整套流程完整拆开给你一份可以直接抄作业的落地参考。1. 为什么用Excel加Robot Framework来管接口自动化1.1 多数接口自动化方案的痛点先说说我现在对这个问题的认识。常见的接口自动化方案无论是用Python的requests直接写脚本还是用Postman导出的Collection再转代码做出来的东西多少都会碰到几个绕不开的坎。第一个坎是“用例即代码”。当你把几十条、上百条用例写成脚本以后用例的维护动作就绑死在写代码的人身上了。业务测试人员想加一条用例只能提需求等你改你休假了需求就堵在那。等你回来改完可能又要处理脚本之间的依赖牵一发而动全身。第二个坎是“参数变化频繁”。接口字段一旦调整你要先去代码里定位对应的地方再判断哪些用例受影响改完之后还要重新跑一遍确认没有影响别处。这个过程极其耗时而且容易漏。第三个坎是“断言逻辑不透明”。脚本里写着很多东西只有自己能看懂别人评审的时候看着一堆代码很难判断覆盖是否完整也很难验证断言是否有效。时间一长用例为什么这么写、当初要防什么bug谁也说不清沦为看起来自动化了、实际靠人肉回归的摆设。1.2 Excel加RF这个组合怎么绕开这些坑用Excel管理用例核心变化是让“用例”和“执行引擎”彻底分离。Excel表格里存的是什么接口、什么参数、什么预期结果团队里任何人都能直接看、直接改。Robot Framework作为一个关键字驱动的自动化框架本身对数据驱动的支持非常自然它不要求你把业务逻辑写成包成一团的代码而是鼓励你把“发请求”“做断言”“取字段”这类动作拆成关键字再通过数据去驱动它们。我实际用下来这个组合带来的最直接好处有三个用例维护成本大幅下降新用例就是在Excel里复制一行改数据不用动代码文件。沟通成本下降测试人员可以拿着Excel跟开发核对接口字段不用把代码截图发来发去。自动化逻辑可以沉淀请求怎么发、断言怎么下这些逻辑封装在关键字里团队内可以复用不用每个人各写一套。1.3 适用场景与边界当然这个方案不是万能药。它更适合中小规模的WebService接口测试场景比如内部系统的REST接口、SOAP接口、或者对外提供的HTTP服务。如果你的团队有上百个微服务、接口调用链非常复杂或者需要高并发压测级别的验证那更适合引入专门的接口测试平台或者更重型的框架。我自己的经验是先想清楚自动化要解决什么核心问题。如果核心诉求是“守住核心接口的回归质量并且用例能跟着业务快速调整”那么Excel加Robot Framework就是很务实的切入点。千万别一上来就想追求脚本写得多么抽象、平台化做得多完整先把日常最痛的那部分覆盖住后面再逐步扩展。2. 动手前的准备环境和目录结构2.1 安装依赖三行命令搞定在Python环境准备好之后安装Robot Framework和配套库只需要几条命令。我用的是Robot Framework 6.x系列配合requests库的封装版本robotframework-requests这两个是目前比较稳定的组合。pip install robotframework pip install robotframework-requests pip install openpyxlrobotframework是主框架robotframework-requests提供了在Robot里直接发HTTP请求的库openpyxl是我用来读写Excel的Python库。之所以用openpyxl而不是直接用Robot里的ExcelLibrary是因为我需要在读取用例的同时做一些字段清洗和格式化比如把Excel里读出来的状态码统一成字符串、把请求体从文本转成字典这些逻辑写在自己封装的Python库里比堆在Robot关键字里舒服得多。安装完成后可以顺手验证一下环境robot --version能正常输出版本号环境就算通了。如果遇到pip安装慢的问题记得换成国内镜像源不然下载robotframework的时候会等到怀疑人生。2.2 目录结构规划项目结构我习惯这样放简洁清楚也方便后面加内容api_auto_test/ ├── testcases/ │ └── api_suite.robot ├── resources/ │ └── ExcelDataReader.py ├── testdata/ │ └── api_cases.xlsx ├── output/ │ ├── log.html │ ├── report.html │ └── output.xml └── run.shtestcases目录放Robot Framework的套件文件也就是执行入口。resources目录放自定义的Python工具库比如读取Excel、提取JSON路径、回写结果。testdata目录放Excel用例文件日常改用例只需要动这个文件。output目录放Robot Framework自动生成的日志和报告。run.sh是启动脚本里面就是一行robot命令robot -d output testcases/api_suite.robot把目录结构固定下来团队成员接手的时候就不会出现“用例文件放哪、报告去哪找”的混乱。很多人做自动化容易忽略这一点其实清晰的项目结构本身就能降低维护门槛。3. 用例模板设计先从一张Excel开始3.1 表头字段怎么定Excel用例模板是整个方案里最值得花时间设计的地方。字段少了写用例的时候会发现很多东西无处安放字段多了维护起来又会觉得繁琐。我在多个项目里反复调整之后沉淀出下面这一套比较通用的字段组合字段说明用例编号唯一标识方便在报告和日志中定位用例名称描述这条用例要验证什么场景是否启用值为“是”才会执行留作临时跳过用例请求方法GET/POST/PUT/DELETE等请求路径接口路径不含域名部分请求头JSON字符串例如 {Content-Type:application/json}请求体JSON字符串POST/PUT时使用预期状态码例如200、201、400、404预期JSON路径需要额外校验的响应字段路径例如 data.user.name预期值上面JSON路径对应的期望值超时(秒)单条用例请求超时时间默认可以留空实际状态码执行后回写执行结果PASS或FAIL执行后回写错误信息断言失败或请求异常时回写你可能会问请求头、请求体写成JSON字符串执行时再转成对象这是不是有点绕直接固定死不行吗我的考虑是这样接口测试的灵活度恰恰来自这里。不同接口的请求头千差万别有的要带Token有的要带不同的Content-Type有的要传文件把这些都设计成Excel里单独的列表格会变得非常臃肿。用JSON字符串放在一个单元格里既保留了格式自由度又不会撑爆表格结构。执行的时候解析JSON字符串即可。3.2 填写规范与示例数据下面是一个两行示例数据方便直观理解用例编号用例名称是否启用请求方法请求路径请求头请求体预期状态码预期JSON路径预期值TC001正常查询用户是POST/api/user/query{Content-Type:application/json}{userId:1001}200data.userName张三TC002用户不存在是POST/api/user/query{Content-Type:application/json}{userId:9999}200data.message用户不存在有几个细节需要养成习惯。请求路径里不要带环境相关的域名域名放到Robot的变量里统一管理。请求头和请求体必须是合法的JSON格式少一个双引号都会导致后续解析直接报错。预期JSON路径我用的是一种简化写法用点号分隔层级比如data.user.name就表示响应体里data对象下的user对象下的name字段。注意预期状态码在Excel里可能是数字格式读出来之后会变成整数或者浮点数。我建议在代码层把它统一转成字符串再用字符串方式去Assert这样能规避很多类型不一致带来的奇怪失败。4. 核心实现读取Excel、循环执行、动态断言4.1 用Python关键字把Excel读出来我不太喜欢在Robot Framework里从头写一遍读取Excel的逻辑那样代码会显得很啰嗦。更稳妥的做法是用Python封装一个读取函数返回Robot可以直接遍历的list of dict结构。这样Robot那边只需要关心“拿到用例之后怎么发请求”不用关心Excel的格式细节。在resources/ExcelDataReader.py里我写了这样的核心函数from openpyxl import load_workbook def read_excel_cases(file_path, sheet_name接口用例): wb load_workbook(file_path, data_onlyTrue) ws wb[sheet_name] headers [cell.value for cell in ws[1]] cases [] for row_idx, row in enumerate(ws.iter_rows(min_row2, values_onlyTrue), start2): if row[0] is None: continue raw dict(zip(headers, row)) case { case_id: raw.get(用例编号), case_name: raw.get(用例名称), method: raw.get(请求方法), path: raw.get(请求路径), headers: raw.get(请求头), body: raw.get(请求体), expected_status: str(raw.get(预期状态码)), json_path: raw.get(预期JSON路径), expected_value: raw.get(预期值), _row: row_idx, } enabled raw.get(是否启用) if enabled 是: cases.append(case) wb.close() return cases为什么用data_onlyTrue因为我需要读取单元格的计算结果而不是公式本身。如果你的Excel里哪些字段用了公式这个参数能保证你拿到的值是公式算出来的结果而不是一串公式文本。为什么要把行号记在case的“_row”字段里因为后面执行完了要按原始行号把结果写回Excel。如果不记录执行阶段就丢失了“这条用例来自第几行”的信息。这个函数还会在读取时过滤掉“是否启用”不为“是”的行。这样Robot那边的FOR循环就简单很多不需要每次判断用例要不要执行。4.2 在Robot Framework里循环跑每条用例接下来是核心的Robot套件设计。我在testcases/api_suite.robot里这样写*** Settings *** Library Collections Library RequestsLibrary Library ../resources/ExcelDataReader.py *** Variables *** ${BASE_URL} http://127.0.0.1:8080 ${CASE_FILE} ../testdata/api_cases.xlsx ${SHEET_NAME} 接口用例 *** Test Cases *** Run API Cases From Excel Create Session api ${BASE_URL} disable_warnings1 ${cases} read excel cases ${CASE_FILE} ${SHEET_NAME} FOR ${case} IN {cases} ${result} Run Single Case ${case} ENDCreate Session先建立一个可复用的HTTP会话后面的请求都会带上这个会话的连接配置。这个会话同时也会管理Cookie遇到需要登录态保持的接口会比较方便。disable_warnings1是让Requests库不要打印那些关于HTTPS证书的告警不然日志会非常嘈杂。FOR循环是Robot Framework 4.0之后推荐的标准写法语法简单直接。这里我不建议用旧版那种:FOR的写法新项目直接上FOR就完了。4.3 断言不止状态码JSON路径校验现在到了最关键的环节怎么把一条Excel用例变成一次真实的接口调用并且完成动态断言。我在同一份Robot文件里定义了几个关键字。第一个关键字负责发请求*** Keywords *** Send Request By Case [Arguments] ${case} ${method} Convert To Upper Case ${case}[method] ${headers} Evaluate json.loads(${case}[headers]) if ${case}[headers] ! else {} modulesjson ${body} Evaluate json.loads(${case}[body]) if ${case}[body] ! else None modulesjson ${resp} POST On Session api ${case}[path] headers${headers} json${body} RETURN ${resp}这里我为了示例简洁先固定用POST On Session来发请求。实际项目中我需要根据用例里的method字段分别调用GET On Session、PUT On Session、DELETE On Session。你也可以用Run Keyword去动态拼关键字名但那样出错时的日志可读性会比较差。我个人的习惯是写一个完整的IF/ELSE分支虽然代码略长但排起错来非常直观。第二个关键字负责跑单条用例的完整流程包括发请求、状态码断言、字段断言、结果回写Run Single Case [Arguments] ${case} ${resp} Send Request By Case ${case} Should Be Equal As Strings ${resp.status_code} ${case}[expected_status] ${json_path} Get From Dictionary ${case} json_path ${expected_value} Get From Dictionary ${case} expected_value IF ${json_path} ! ${json} Set Variable ${resp.json()} ${actual_value} get value by json path ${json} ${json_path} Should Be Equal As Strings ${actual_value} ${expected_value} END RETURN ${case}这里有一个小细节状态码断言理应放在字段断言前面因为字段断言依赖响应体是合法JSON如果接口返回500或者超时响应体可能不是JSON先校验状态码能给出更明确的失败信息。get value by json path需要Python库提供支持。我在ExcelDataReader.py里增加了一个简化版本的路径取值函数def get_value_by_json_path(json_data, path): if not path: return None current json_data for key in path.split(.): if isinstance(current, dict): current current.get(key) elif isinstance(current, list): try: current current[int(key)] except (ValueError, IndexError): return None else: return None return current这个函数只支持点分路径对付常见的嵌套JSON已经够用。如果团队里有更复杂的断言需求比如需要判断数组长度、需要正则匹配、需要多级条件过滤那可以升级成jsonpath-ng这类库来解析$..这种更灵活的表达式。最开始不需要一步到位先跑通再增强是更现实的路线。提示在Robot Framework里对dict取值的写法很有讲究。${case}[method]这种写法能直接取到键对应的值但如果键不存在会直接报错。所以Robot调用前我宁可在Python读取函数里把字段都补齐也不要依赖Robot侧的容错。5. 执行结果回写与日志排查5.1 把结果直接写回Excel接口跑完不能只把结果留在Robot的日志里团队更习惯看Excel里的最后一列是PASS还是FAIL。所以我在ExcelDataReader.py里又加了一个回写函数def write_result_to_excel(file_path, sheet_name, row_number, actual_status, result, message): wb load_workbook(file_path) ws wb[sheet_name] ws.cell(rowrow_number, column12).value actual_status ws.cell(rowrow_number, column13).value result ws.cell(rowrow_number, column14).value message wb.save(file_path) wb.close()每次只保存当前工作簿这样在批量执行过程中不会积累文件句柄避免Windows系统下常见的“文件被占用无法写入”问题。如果用例数量特别大每次都打开保存整个Excel文件确实有点慢但对于几百条用例来说这个耗时完全在可接受范围内。在Robot那侧Run Single Case里可以包一层异常处理。我习惯这样写Run Single Case [Arguments] ${case} TRY ${resp} Send Request By Case ${case} Should Be Equal As Strings ${resp.status_code} ${case}[expected_status] ${json_path} Get From Dictionary ${case} json_path ${expected_value} Get From Dictionary ${case} expected_value IF ${json_path} ! ${json} Set Variable ${resp.json()} ${actual_value} get value by json path ${json} ${json_path} Should Be Equal As Strings ${actual_value} ${expected_value} END write result to excel ${CASE_FILE} ${SHEET_NAME} ${case}[_row] ${resp.status_code} PASS EXCEPT ${message} TYPE write result to excel ${CASE_FILE} ${SHEET_NAME} ${case}[_row] N/A FAIL ${message} Log ${message} levelERROR ENDTRY/EXCEPT是Robot Framework 5.0引入的语法如果你用的是旧版本Robot需要换一种写法比如Run Keyword And Expect Error配上自定义关键字但可读性和排查体验都会差不少。所以我有意把示例建立在比较新的版本上强烈建议团队升级到5.0以上。一旦某条用例断言失败异常被捕获后错误信息会被写进Excel同时Robot自己也会在log里打一条ERROR日志。这样你在Excel里看到FAIL不用切换到log.html也能大概知道问题是什么。5.2 结合log.html和report.html排查问题Robot Framework自动生成的三个产物里report.html是结果概览log.html是详细的执行日志。排查失败用例的时候我一般会先看Excel回写的错误信息如果不够再打开log.html搜索对应的用例编号。log.html里会展示每一步关键字的入参和返回值比如Send Request By Case收到的${case}字典、POST On Session返回的响应体、断言关键字比较的两个值。这个信息比单纯在Python里print要直观得多也是我选择Robot FrameWork而不是自己写一套脚本的好处之一。有个小技巧在Robot关键字里尽量把“请求路径”“请求体”“响应体”用Log关键字打出来。虽然RequestsLibrary本身会记录部分信息但自己记录能保证格式完全可控。否则遇到某些接口返回极大响应体时Robot日志会被刷得惨不忍睹连正常内容都找不到。6. 实战中踩过的坑和解决记录6.1 Excel中文编码和单元格格式问题Excel文件落地后最常见的问题就是中文乱码和内容格式不一致。我自己就遇到过好几次这种事。先说编码。用openpyxl读写xlsx格式内部管理是Unicode所以正常读写中文不会乱码。真正的坑在于如果团队有人把Excel另存成了xls或者CSV文件再放进测试数据目录那代码读取时要么报格式不支持要么就会出现编码解析问题。所以我的处理方式是明确约定只支持xlsx格式所有用例文件统一放在testdata目录。任何人提交文件之前检查一下后缀。第二个坑是单元格格式。Excel默认会把200这种数字当整数处理把001这种字符串当数字处理成1。预期状态码被读成整数之后在Robot里跟字符串比对就会失败。解决的办法是我前面提到的在Python读取函数里统一转换成str。这一小行代码省了我排查无数个类型不匹配的失败。第三个坑更隐蔽单元格里有不可见字符比如Excel复制粘贴时带进来的换行符、制表符。这些字符不会在界面上直接显示但进入Robot以后会导致断言值对比失败。我的排查方法是写一个临时脚本把读出来的case字段repr打印出来。一看就明白原来值前后多了一个\n。后来我在读取函数里加了strip()这个问题就彻底没了。6.2 接口依赖与Token传递接口自动化里最麻烦的不是发请求而是接口之间的依赖。很多系统登录之后才能访问业务接口Token如果每次手工填到Excel里用例文件就失去了自动化意义。我是这样处理的。首先在Excel里建一个配置sheet页存放一些全局变量比如登录接口的账号密码、Token的有效期、当前使用哪个环境。然后在Robot里加一个“登录并取Token”的关键字执行入口先调用登录接口把Token存成Suite级别的变量。后面所有用例的请求头里都可以用${token}来引用。实际做的时候大概长这样Login And Get Token Create Session auth ${BASE_URL} ${headers} Create Dictionary Content-Typeapplication/json ${body} Create Dictionary username${ACCOUNT} password${PASSWORD} ${resp} POST On Session auth /api/login headers${headers} json${body} Should Be Equal As Strings ${resp.status_code} 200 ${token} get value by json path ${resp.json()} data.token Set Suite Variable ${token}然后在Excel的请求头单元格里写{Content-Type:application/json, Authorization:Bearer ${token}}Robot在Evaluate解析的时候会先把带${token}的字符串替换成全局变量的实际值再去解析JSON所以这个方案是能直接跑的。这比在Excel里维护一个独立的Token列再在代码里拼加请求头要省事得多。6.3 测试数据隔离和用例执行顺序接口自动化踩过的另一个大坑是测试数据之间互相污染。比如TC001创建了一个资源TC002去查询这个资源本意是一对依赖用例但因为TC001在某个环境下执行失败TC002的预期数据就没了整个回归一片红。我的建议是每条接口用例尽量设计成独立可重复执行不要依赖其他用例的执行结果。如果业务逻辑确实要求先创建再查询那么你就把这套交互放在一条用例里用连续性断言去覆盖而不是拆成两条让它们隐式依赖。隐式依赖是非常危险的它会让失败的分析变得极其复杂。执行顺序上也有一点经验Robot的FOR循环就是按照Excel的行顺序执行的。如果项目里暂时避免不了某些前后置依赖那就确保把前置用例放在上面的行不要在Excel里随意乱排。当然更高级的做法是引入pabot做并行执行但并行会带来更高的数据隔离要求初期不建议并行。7. 后续可以怎么扩展这套Excel加Robot Framework的方案跑到稳定阶段之后后面自然会有一些扩展方向。第一个方向是环境切换。目前BASE_URL写死在Robot的Variables里为了方便测试和预发环境来回切可以把环境配置放到一个Python文件或者配置文件里通过命令行参数传入。Robot Framework本身支持通过--variable参数覆盖变量这样CI里跑不同环境的时候就不用来回改Excel了。第二个方向是CI集成。把robot命令接到常见的CI流水线里每次代码提交后自动跑接口回归产出robot报告上传到CI平台。这个做法不复杂效果却立竿见影接口质量会从“靠人来盯”变成“由流水线守门”。第三个方向是报告增强。Robot原生报告已经不错但如果团队希望把结果汇总到自己的测试平台可以解析output.xml把每个用例的响应时间、状态码、断言结果提取出来写入内部系统。很多测试平台都有提供解析Robot XML的现成依赖不用自己从零写。如果让我重新选一次我可能还是会用Excel加Robot Framework来做接口自动化的第一版。不是说它完美而是它足够简单简单到团队里的每个人都能理解用例是怎么组织的也足够灵活灵活到能覆盖WebService接口测试的大部分核心场景。自动化用例不是越多越好而是能被人持续维护、能在每次发布前真正减少手工回归工作量才有价值。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑