资讯动态

基于unittest与Excel的接口自动化测试框架设计与实现

发布时间:2026/10/13 9:00:10 来源:尧图企业网站定制
1. 接口自动化测试框架选型与整体设计思路做接口自动化这件事很多人第一反应是上 pytest、上 requests、上 allure一套组合拳打下来确实漂亮。但如果你所在的项目组里测试同学写代码的经验参差不齐或者你希望非技术背景的同事也能参与维护用例那 Python 标准库里的 unittest 加上 Excel 驱动反而是最稳、最容易落地的方案。我自己在几个不同规模的项目里都试过这套组合实测下来它的最大优势不是技术多先进而是门槛低、可交接、易维护。这套方案的核心逻辑其实就一句话用 Excel 管用例数据和断言用 unittest 管执行和报告用 xlrd 读、用 xlsxwriter 写。为什么是这两个库而不是 openpyxl 或 pandas原因很实际——xlrd 读取老版本 xls 和新版本 xlsx 都很稳API 简单到几乎不用查文档xlsxwriter 写出的文件格式干净支持单元格样式、条件格式、图表生成测试报告时排版可控。pandas 虽然强大但引入它意味着多一层依赖而且它对单元格样式的控制力很弱写出来的报告不好看。整体架构我一般分成四层用例数据层Excel、数据读取层xlrd 封装、测试执行层unittest TestCase、报告输出层xlsxwriter。这四层各司其职数据层和代码层完全解耦改用例不用动代码改代码不影响用例。这个设计的好处在于当接口字段变了你只需要在 Excel 里改一下请求参数和预期结果不需要去翻 Python 文件。对于迭代频繁的项目这一点能省下大量维护时间。注意xlrd 从 2.0 版本开始不再支持 xlsx 格式只支持 xls。如果你用的是 xlrd 2.x要么降级到 1.2.0要么改用 openpyxl 读取。这一点后面会详细说。2. Excel 用例设计的核心细节与实操要点2.1 用例表结构怎么设计才合理Excel 用例表的设计直接决定了后续代码的复杂度和可维护性。我见过太多人把用例表设计得花里胡哨结果写读取逻辑时痛苦不堪。经过多次迭代我总结出一个比较通用的列结构你可以直接抄列名说明示例case_id用例编号唯一标识TC_001case_name用例名称描述测试目的正常登录method请求方法POSTurl接口路径/api/loginheaders请求头JSON 字符串{Content-Type:application/json}params请求参数JSON 字符串{username:admin,password:123456}expected_code预期 HTTP 状态码200expected_body预期响应体关键字段JSON 字符串{code:0,msg:success}is_run是否执行Y/NYresult实际结果回写用留空这个结构的好处是每一列职责单一读取逻辑可以按列名索引不依赖列的顺序。很多人喜欢用列号比如第 3 列是 method一旦插入一列整个代码全崩。用列名索引虽然多写几行代码但稳定性高得多。2.2 为什么用 JSON 字符串存请求参数请求参数和预期结果我强烈建议用 JSON 字符串存而不是拆成多列。原因有三第一接口参数结构可能很复杂嵌套字典、数组都很常见拆列根本拆不干净第二JSON 字符串在 Python 里用json.loads()一行就能转成字典非常方便第三预期结果用 JSON 存可以做灵活的字段比对而不是死板的字符串相等。实际操作中你可以在 Excel 里直接写{username:admin,password:123456}读取后用json.loads()解析。如果某个参数需要动态生成比如时间戳、随机数可以在字符串里用占位符比如{timestamp:${timestamp}}读取后再做替换。这个技巧后面会详细讲。2.3 多环境配置怎么处理真实项目里接口地址通常有测试环境、预发环境、生产环境之分。我的做法是在 Excel 里单独放一个 Sheet 叫config里面用键值对存环境地址keyvaluetest_hosthttp://test.example.compre_hosthttp://pre.example.comprod_hosthttp://prod.example.com然后在用例表的 url 列里只写路径比如/api/login执行时根据当前环境拼接 host。这样切换环境只需要改一个配置项不用动用例。这个设计在多个项目里都验证过非常实用。实操心得config Sheet 里还可以放全局请求头、超时时间、重试次数等配置。我一般会把超时时间设成 10 秒重试次数设成 2 次避免网络抖动导致的偶发失败。3. 数据读取层与执行层的完整实现3.1 xlrd 读取 Excel 的封装技巧xlrd 的基本用法很简单但要用好需要做一些封装。下面是我常用的读取函数import xlrd import json def read_excel(file_path, sheet_name): workbook xlrd.open_workbook(file_path) sheet workbook.sheet_by_name(sheet_name) # 第一行作为列名 headers [sheet.cell_value(0, col) for col in range(sheet.ncols)] cases [] for row_idx in range(1, sheet.nrows): row_data {} for col_idx in range(sheet.ncols): row_data[headers[col_idx]] sheet.cell_value(row_idx, col_idx) cases.append(row_data) return cases这段代码的核心是用第一行做列名映射后续所有取值都通过列名而不是列号。这样即使 Excel 列顺序调整代码也不用改。另外xlrd 读取单元格时数字会变成 float比如 200 会读成 200.0需要在代码里做类型转换。我一般会在读取后统一处理如果是 float 且是整数就转成 int。还有一个坑xlrd 读取空单元格返回空字符串但如果是合并单元格只有左上角有值其他位置是空。所以用例表里尽量不要用合并单元格否则读取逻辑会变得很复杂。3.2 unittest 测试用例的动态生成unittest 默认的写法是每个用例写一个 test 方法但接口自动化用例可能有几百条不可能手写几百个方法。这时候需要用动态生成测试方法的技巧import unittest class TestApi(unittest.TestCase): pass def generate_test(case): def test(self): # 执行接口请求和断言 response send_request(case) self.assertEqual(response.status_code, int(case[expected_code])) return test # 动态添加方法 cases read_excel(cases.xlsx, Sheet1) for case in cases: if case[is_run] Y: test_method generate_test(case) setattr(TestApi, test_ case[case_id], test_method)这个技巧的关键是setattr它能在运行时给类添加方法。每个用例生成一个独立的 test 方法unittest 就能自动发现并执行。方法名必须以test_开头这是 unittest 的命名约定。注意动态生成方法时闭包变量要小心。上面的generate_test函数接收 case 参数避免了闭包捕获同一个变量的问题。如果你直接在循环里定义函数所有方法可能都会用最后一个 case 的数据。3.3 请求发送与断言逻辑请求发送我一般用 requests 库封装一个通用函数import requests import json def send_request(case, host): url host case[url] method case[method].upper() headers json.loads(case[headers]) if case[headers] else {} params json.loads(case[params]) if case[params] else {} if method GET: response requests.get(url, headersheaders, paramsparams, timeout10) elif method POST: response requests.post(url, headersheaders, jsonparams, timeout10) # 其他方法类似 return response断言部分我一般分两层先断言 HTTP 状态码再断言响应体关键字段。响应体断言用 JSON 解析后逐字段比对而不是字符串相等。这样即使响应体多了无关字段也不会导致用例失败。expected_body json.loads(case[expected_body]) actual_body response.json() for key, value in expected_body.items(): self.assertEqual(actual_body.get(key), value)这种断言方式灵活且稳定是我在多个项目里验证过的最佳实践。4. 测试报告生成与结果回写4.1 用 xlsxwriter 生成可读性强的报告xlsxwriter 写 Excel 的能力很强我一般会生成一个包含多个 Sheet 的报告汇总 Sheet、详情 Sheet、失败用例 Sheet。汇总 Sheet 放执行时间、用例总数、通过数、失败数、通过率详情 Sheet 放每条用例的请求参数、响应结果、断言结果失败用例 Sheet 只放失败的方便快速定位。import xlsxwriter def write_report(results, output_path): workbook xlsxwriter.Workbook(output_path) # 定义样式 header_format workbook.add_format({bold: True, bg_color: #D7E4BC, border: 1}) pass_format workbook.add_format({bg_color: #C6EFCE, border: 1}) fail_format workbook.add_format({bg_color: #FFC7CE, border: 1}) # 汇总 Sheet summary_sheet workbook.add_worksheet(汇总) summary_sheet.write(0, 0, 用例总数, header_format) summary_sheet.write(0, 1, len(results), header_format) # ... 其他汇总信息 # 详情 Sheet detail_sheet workbook.add_worksheet(详情) headers [用例编号, 用例名称, 请求参数, 预期结果, 实际结果, 状态] for col, header in enumerate(headers): detail_sheet.write(0, col, header, header_format) for row, result in enumerate(results, start1): detail_sheet.write(row, 0, result[case_id]) # ... 其他列 if result[status] PASS: detail_sheet.write(row, 5, PASS, pass_format) else: detail_sheet.write(row, 5, FAIL, fail_format) workbook.close()xlsxwriter 的样式系统很灵活通过颜色区分通过和失败报告一眼就能看懂。我一般还会设置列宽和自动换行避免内容被截断。4.2 结果回写到原始用例表除了生成独立报告把执行结果回写到原始用例表的result列也很实用。这样下次打开用例表就能看到上次执行的结果。但 xlrd 只能读不能写所以回写需要用 xlsxwriter 重新生成一个文件或者用 openpyxl 直接修改原文件。我的做法是读取原文件执行用例然后用 xlsxwriter 生成一个新文件包含原始用例数据加上 result 列。这样原始文件保持不变新文件作为执行记录存档。def write_back(cases, results, output_path): workbook xlsxwriter.Workbook(output_path) sheet workbook.add_worksheet(Sheet1) headers list(cases[0].keys()) for col, header in enumerate(headers): sheet.write(0, col, header) for row, case in enumerate(cases, start1): for col, header in enumerate(headers): if header result: sheet.write(row, col, results[row-1][status]) else: sheet.write(row, col, case[header]) workbook.close()这个回写逻辑简单直接生成的文件既保留了原始用例又加上了执行结果方便追溯。实操心得报告文件名我一般用report_年月日_时分秒.xlsx的格式避免多次执行覆盖。同时会在汇总 Sheet 里记录执行环境的 host方便区分不同环境的执行结果。5. 常见问题与排查技巧实录5.1 xlrd 版本兼容问题这是最容易踩的坑。xlrd 2.0 以后只支持 xls读取 xlsx 会直接报错xlrd.biffh.XLRDError: Excel xlsx file; not supported。解决办法有两个一是降级到pip install xlrd1.2.0二是改用 openpyxl 读取。我一般推荐降级因为 xlrd 1.2.0 的 API 和 2.0 完全兼容代码不用改。5.2 中文乱码问题Excel 里的中文读取出来是乱码通常是编码问题。xlrd 读取时默认用 UTF-8一般不会乱码。如果遇到乱码检查 Excel 文件本身是不是用其他编码保存的。另外写入报告时xlsxwriter 默认支持中文不需要额外设置。5.3 请求参数中的特殊字符如果请求参数里包含中文、空格、特殊符号JSON 序列化时要注意转义。我一般用json.dumps(params, ensure_asciiFalse)来保留中文避免被转成 Unicode 编码。5.4 用例依赖问题有些接口需要先登录拿到 token后续接口才能调用。这种依赖关系在 Excel 里不好表达。我的做法是在 config Sheet 里放一个token字段登录用例执行后把 token 写进去后续用例读取时自动带上。或者用 unittest 的setUpClass方法在所有用例执行前先登录一次。5.5 常见问题速查表问题现象可能原因解决方法xlrd 读取 xlsx 报错xlrd 版本过高降级到 1.2.0数字读成 floatxlrd 默认行为读取后做类型转换合并单元格读取为空只有左上角有值避免使用合并单元格动态方法不执行方法名不以 test_ 开头检查命名约定闭包变量错误循环中定义函数用工厂函数包裹报告中文乱码编码问题用 ensure_asciiFalse请求超时网络或服务问题设置 timeout 和重试断言失败但实际正确响应体多了字段用字段比对而非字符串比对避坑技巧用例表里的is_run列非常有用。调试阶段可以把不相关的用例设成 N只跑当前关注的几条节省时间。上线前再全部打开跑一遍。6. 框架扩展与持续优化方向这套框架跑通之后可以做一些扩展让它更好用。比如加入日志记录每次请求和响应都写到日志文件方便排查问题加入邮件通知执行完自动发报告给相关同事加入定时任务用系统的计划任务每天定时跑一遍。这些扩展都不复杂按需添加即可。另一个优化方向是用例参数化。同一条用例如果只是某个参数不同可以在 Excel 里写多行用同一个 case_name 加不同后缀。读取时自动展开成多条用例。这样能减少重复用例的维护成本。还有一点值得提的是数据驱动和关键字驱动的结合。目前这套方案是数据驱动用例逻辑写在代码里。如果进一步抽象可以把请求方法、断言方式也做成关键字在 Excel 里配置那就是关键字驱动了。不过关键字驱动对用例设计能力要求更高团队规模不大时数据驱动已经够用。我个人在实际操作中的体会是这套方案最大的价值不在于技术多高深而在于它能让测试团队里不同水平的人都能参与进来。会写代码的维护框架不会写代码的维护 Excel 用例分工明确协作顺畅。踩过几次坑之后我把所有封装都做得尽量简单宁可多写几行代码也不引入复杂的抽象。毕竟自动化测试框架的第一要务是稳定可靠而不是炫技。

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

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

免费获取报价 →
↑