ARTICLE DETAIL

资讯详情

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

Python接口自动化实战:pytest参数化、数据驱动与断言体系

Python接口自动化实战:pytest参数化、数据驱动与断言体系 2019年那会儿我还在一个做电商系统的团队里每天抱着Postman一个一个点接口点完看返回、截图、贴到群里一上午能测五六个接口就算效率不错。后来接口数量涨到两三百个前端、客户端、小程序都在调同一套服务端一改版就要回归手工点真的会点出工伤。后来下了决心把接口测试迁到Python pytest requests这套技术栈上核心就做三件事参数化测试、数据驱动测试、断言。这三件事做扎实之后回归一个模块从半天缩到几分钟而且很多之前靠“手气”才能发现的边界问题变成了用例里的一组数据跑一遍就知道好不好使。这篇文章不聊虚的就直接讲我实际落地这套接口测试方案时的选型思路、代码结构、踩过的坑。适合三种人看手工点点点想转自动化的测试同学、已经用Postman/JMeter/Apifox做接口测试但觉得组织用例越来越吃力的同学、以及刚接触Python想在项目里搭一套接口自动化模板的开发者。1. 从手工点接口到自动化测试你真正缺的是这三个能力1.1 手工测试的瓶颈不在“点”而在“回归”先说说我之前的真实状态。单个接口调试Postman、Apifox这类工具其实特别好用尤其是mock模拟接口调不通的时候用工具先验一下请求格式、看响应结构效率非常高。JMeter做压测、做简单的多用户并发也有它的优势。但一旦进入“回归测试”场景问题就来了。某个接口改动后要把正常参数、错误密码、空用户名、超长用户名、手机号格式错误这些用例全部重新点一遍哪怕只是改了一个字段校验手工点也要花十几分钟。改得频繁一点一天光回归就没了。另一个更隐蔽的问题是手工点通常只看响应里的code是不是0、msg是不是success很少会去校验返回字段里某个嵌套值对不对。接口返回200、code也是0但里面某个金额计算错了手工很难盯出来。自动化测试想解决的就是两件事同一段验证逻辑能不能在多种数据下反复执行以及断言能不能覆盖到业务规则层面而不是停留在表面。1.2 为什么选了Python pytest requests而不是继续用工具不是工具不行是工具不适合做大规模的、和代码库深度耦合的接口自动化。Postman也有runner和脚本但你要是想连数据库校验数据、从测试环境造数据、按复杂规则动态生成请求体就非常别扭。JMeter的强项是压测和协议模拟断言和场景组织能力偏弱用例一多脚本文件管理起来也痛苦。我选Python的理由很实在生态成熟pytest的参数化、fixture、插件体系几乎是为我们这个场景量身订做的requests库写接口请求又足够简洁。团队里新同学上手Python的成本也比较低会点基础语法就能看懂用例。还有一个隐性收益测试代码就是一个可执行的项目。数据放data目录、公共方法放common目录、用例按模块拆开这本身就是一份活的接口文档比wiki上那条永远不更新的文档靠谱得多。1.3 参数化、数据驱动、断言三者的关系我见过不少团队做了接口自动化但用例写法还是“一个接口一个函数函数里面写死数据”其实那只算是“把手工操作录成了代码”没有发挥自动化的核心价值。真正让用例规模可控的三个能力是参数化测试同一段测试逻辑喂不同参数组合校验不同的期望结果。一个登录接口写一个测试函数就够了十组登录数据对应十种场景。数据驱动测试把测试数据从代码里拆出去放到JSON、YAML或者Excel里。测试逻辑不关心数据长什么样只负责执行和断言。断言判断“这次请求到底对不对”的规则集合从HTTP状态码到业务返回值再到数据库落库状态。它们三个是递进关系。参数化解决“怎么让一段逻辑跑多组数据”数据驱动解决“这些数据放哪里、谁去维护它”断言解决“跑完之后怎么算通过”。文章后面每一个都会展开。2. 工程基座目录设计、依赖管理与环境切换动手写用例之前先把工程结构搭好。这一步偷懒了后面用例写多了会非常难受。2.1 初始化环境和依赖我习惯每个项目建独立虚拟环境避免本机多项目之间的包冲突。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pytest requests pytest-html pytest-rerunfailures pyyaml openpyxl jmespath pymysql pip freeze requirements.txt依赖里稍微解释一下pytest测试框架参数化和fixture的核心。requests发HTTP请求。pytest-html生成HTML测试报告。pytest-rerunfailures处理偶发网络波动导致的失败后面实战里会用到。pyyaml读取YAML数据文件。openpyxl读取Excel里的测试数据。jmespath做复杂的JSON字段提取断言的时候特别好用。pymysql做数据库校验不是每个团队都需要但如果接口返回“成功”而库里没数据这种bug用代码是验不出来的。2.2 一个用了很久的目录结构api_auto_test/ ├── config/ │ ├── test.yaml │ ├── staging.yaml │ └── prod.yaml ├── common/ │ ├── __init__.py │ ├── requests_util.py │ ├── file_loader.py │ └── db_util.py ├── data/ │ ├── login_cases.yaml │ ├── order_cases.yaml │ └── user_cases.json ├── testcases/ │ ├── __init__.py │ ├── conftest.py │ ├── test_login.py │ └── test_order.py ├── report/ ├── pytest.ini ├── requirements.txt └── README.md目录划分的逻辑很简单config放环境配置common放所有公共封装data放测试数据testcases放测试用例report放测试报告。团队里任何人拿到这个项目不需要问“这个文件放哪”一眼就能找到。2.3 环境切换别写死用参数控制很多项目一上来就把base_url写在用例里这非常坑。测试环境、联调环境、预发布环境的地址不一样每次切换都要改代码而且容易改漏。我用的方案是环境配置放到YAML文件里通过pytest命令行参数动态选择。# config/test.yaml base_url: http://127.0.0.1:8000 db: host: 127.0.0.1 port: 3306 user: root password: 123456 database: test_dbconftest.py里注册一个自定义参数然后根据参数加载对应的配置import pytest import yaml def load_env_config(env_name): with open(fconfig/{env_name}.yaml, r, encodingutf-8) as f: return yaml.safe_load(f) def pytest_addoption(parser): parser.addoption(--env, actionstore, defaulttest, help指定运行环境: test/staging/prod) pytest.fixture(scopesession) def env_config(request): env_name request.config.getoption(--env) return load_env_config(env_name)这样运行用例的时候只需要pytest --env test pytest --env staging所有用例从env_config这个fixture里拿配置不用在代码里改任何东西。3. 参数化测试pytest.mark.parametrize 的进阶用法与数据闭环参数化是pytest里最核心的功能之一。理解它的本质比死记用法重要得多。3.1 参数化的本质同一段逻辑对应多组输入和期望用一个登录接口的例子。第一种写法是每个场景写一个测试函数def test_login_success(): resp requests.post(http://127.0.0.1:8000/api/login, json{username: admin, password: 123456}) assert resp.status_code 200 assert resp.json()[code] 0 def test_login_wrong_password(): resp requests.post(http://127.0.0.1:8000/api/login, json{username: admin, password: wrong}) assert resp.status_code 200 assert resp.json()[code] 1001这样写看起来直观但场景一多每个函数只是数据不同代码里大量重复。更关键的是如果登录接口的逻辑改了比如响应结构从code变成了status你要改十几个函数。用parametrize改写之后一个函数就能覆盖所有场景import pytest import requests pytest.mark.parametrize(username,password,expected_code,expected_msg, [ (admin, 123456, 0, success), (admin, wrong, 1001, 用户名或密码错误), (, 123456, 1002, 用户名不能为空), (admin, , 1003, 密码不能为空), ]) def test_login(username, password, expected_code, expected_msg): resp requests.post(http://127.0.0.1:8000/api/login, json{username: username, password: password}) body resp.json() assert resp.status_code 200 assert body[code] expected_code assert body[msg] expected_msg测试函数只有一个pytest会按照参数组数生成多条测试用例。跑一遍登录接口四个场景全部覆盖哪个场景挂了直接看用例名里的参数就知道。3.2 多参数、组合参数和自定义用例名parametrize支持的参数个数没有上限。接口测试里面常见的是“请求参数 期望状态码 期望业务码 期望消息”这样一组四个参数就能把输入和期望都表达完整。如果接口有多个互相独立的输入维度比如分页查询里的page和page_size你可以叠加多个parametrize它会自动做笛卡尔积组合pytest.mark.parametrize(page, [1, 2, 3]) pytest.mark.parametrize(page_size, [10, 20]) def test_query_list(page, page_size): ...这样会生成2乘3等于6条用例把分页参数的组合全部覆盖。注意叠加方式写在函数上方的parametrize离函数越近越先参与组合。用例多了之后pytest默认的用例名会变成参数值的拼接比如test_login[admin-wrong-1001-用户名或密码错误]。参数里有中文长文本时会很难看所以最好用ids给每条用例起一个简短的名字pytest.mark.parametrize(username,password,expected_code,expected_msg, [(admin, wrong, 1001, 用户名或密码错误)], ids[密码错误]) def test_login(username, password, expected_code, expected_msg): ...这样报告里显示的是test_login[密码错误]一眼就知道这条用例在测什么。3.3 参数化不等于数据驱动但它是数据驱动的底层机制参数化的方式有两种一种是直接把参数列表写在装饰器里适合参数少、场景固定的情况另一种是从外部数据文件读取参数列表再通过parametrize传入测试函数。后者其实就是数据驱动测试的常见实现方式。数据驱动强调的是“数据”与“逻辑”分离而实现分离的手段就是参数化。所以参数化是把数据文件和测试函数连接起来的那根线数据文件提供了什么pytest就跑什么。4. 数据驱动测试JSON、YAML、Excel 三种落地方式对比把测试数据从代码里拎出来是让测试项目长期可维护的关键一步。这部分我讲三套可落地的方案还有它们的适用边界。4.1 数据驱动到底解决了什么问题项目做到后面真正维护测试用例的人可能不是写代码的人而是业务测试同学。他们不懂Python但你给他们一个Excel或者YAML文件让他们填“用户名、密码、期望错误码”这个门槛就低很多。数据驱动要做的事情就是把这一层彻底解耦测试代码不关心具体有哪些用例数据它只负责“拿到一条数据、发起请求、按期望字段校验结果”。数据文件里加一条数据就等于新增一条测试用例。格式选择上我是这么看的JSON是通用性最强的几乎所有语言都原生支持YAML写起来更舒服有注释、不用写大括号逗号Excel最适合业务同学维护但读取和校验稍微繁琐。4.2 JSON数据驱动最通用、最少踩坑先建一个数据文件data/login_cases.json[ { case_name: 登录成功, username: admin, password: 123456, expected: { code: 0, msg: success } }, { case_name: 密码错误, username: admin, password: wrong, expected: { code: 1001, msg: 用户名或密码错误 } } ]测试代码里写一个读取函数配合parametrize使用import json import pytest import requests def load_cases(path): with open(path, r, encodingutf-8) as f: return json.load(f) login_cases load_cases(data/login_cases.json) pytest.mark.parametrize(case, login_cases, idslambda c: c[case_name]) def test_login(case): resp requests.post(http://127.0.0.1:8000/api/login, json{username: case[username], password: case[password]}) body resp.json() expected case[expected] assert resp.status_code 200 assert body[code] expected[code] assert body[msg] expected[msg]ids用lambda表达式读取每条数据里的case_name字段报告里显示的就是“登录成功”“密码错误”可读性非常好。这里有个细节读取文件要在模块级别执行也就是login_cases load_cases(...)这行放在函数外面。这样整个模块只读取一次文件而不是每条用例执行时都重新读一遍减少IO开销。4.3 YAML数据驱动适合手工维护的场景YAML和JSON的核心差别是“人友好度”。YAML支持注释可以写“这条用例依赖前置条件”“这个值是临时改的”这种说明JSON就不行。先装依赖pip install pyyaml数据文件data/order_cases.yaml- name: 下单成功-普通商品 payload: sku_id: 1001 quantity: 2 address_id: 10 expect: code: 0 msg: success - name: 下单失败-库存不足 payload: sku_id: 1002 quantity: 999 address_id: 10 expect: code: 2003 msg: 库存不足读取和使用方式import yaml import pytest def load_yaml_cases(path): with open(path, r, encodingutf-8) as f: return yaml.safe_load(f) order_cases load_yaml_cases(data/order_cases.yaml) pytest.mark.parametrize(case, order_cases, idslambda c: c[name]) def test_create_order(case): ...YAML的缩进很敏感Tab和空格混用会直接报错。如果团队里新人多建议写一个README说明文件格式或者在CI里加一步YAML语法校验。4.4 Excel/CSV数据驱动业务同学也能上手维护有些团队的数据文件是由业务同学直接维护的他们最熟悉的工具是Excel。这时候用openpyxl读Excel更合适。pip install openpyxl写一个通用读取函数import openpyxl def load_excel_cases(path, sheet_nameSheet1): wb openpyxl.load_workbook(path, data_onlyTrue) ws wb[sheet_name] rows list(ws.iter_rows(values_onlyTrue)) if not rows: return [] headers rows[0] return [dict(zip(headers, row)) for row in rows[1:] if any(row)]表格第一行是字段名后面每一行是一条用例。比如case_nameusernamepasswordexpected_codeexpected_msg登录成功admin1234560success密码错误adminwrong1001用户名或密码错误读出来之后每条数据是一个dictkey是表头value是单元格内容。后面配合parametrize的方式和JSON/YAML完全一样。用Excel要特别注意类型问题。excel单元格里写“1001”会被读成数字写“001”可能变成1所以如果字段是字符串类型的编码最好在Excel里把单元格格式设置成文本或者在读取时做一次类型转换。4.5 数据驱动的边界不是所有数据都适合外部化我见过一种走极端的做法把所有数据全部塞到Excel里连一个固定不变的常量也要维护。这样反而增加了维护成本。我的取舍原则是经常变化、组合很多的数据放到外部文件。比如接口的边界值、不同用户身份、不同状态的订单ID。固定不变的数据比如接口路径、固定请求头、固定环境地址直接写在配置或代码里。一个用例只出现一次的特殊数据直接写在parametrize装饰器里就够了没必要为了“数据驱动”而驱动。数据驱动的目的永远是降低维护成本不是为了形式好看。5. 断言的四个层级从HTTP状态码到数据库校验断言是最容易被低估的部分。很多团队“自动化”跑起来了但断言就是assert resp.status_code 200等于白测。因为接口只要不报5xx用例就全绿真正的业务错误根本发现不了。我后来总结了一套断言的四个层级每个层级覆盖一类问题。5.1 第一层HTTP状态码这一层是最基础的。200代表请求被服务端正常处理404路径不存在500服务端内部错误401未认证403无权限。但接口测试里HTTP状态码只是“传输层”的状态它不能代表业务是否成功。一个登录接口返回200但业务code可能是1001用户名或密码错误这属于正常的业务交互不是系统Bug。所以我的规范是基本每个用例都要校验HTTP状态码但不能只校验HTTP状态码。5.2 第二层业务状态码这是接口测试区别于爬虫测试、UI测试的核心。绝大多数后端接口会在响应体里带一个业务code和一个msg用来看这个请求在业务上是否成功。{ code: 1001, msg: 用户名或密码错误, data: null }断言业务code的逻辑很简单body resp.json() assert body[code] expected_code assert body[msg] expected_msgexpected_code和expected_msg从哪里来通常从数据文件里作为测试数据传入这样不同场景对应不同的期望值。这里有一个很常见的坑业务code的定义在不同接口之间可能不统一。有的接口成功是0有的是200有的是success。建议在项目的公共断言函数里做一个适配层统一管理这些差异不要让每个用例各写各的。5.3 第三层响应体结构和关键字段只校验code还有一个风险服务端改了响应体结构比如原来返回data.user_name现在改成data.usernamecode和msg都没变但前端取不到数据了。这种情况靠断言code是发现不了的。第三层就是校验响应里的关键字段尤其是嵌套结构。我推荐用jmespath来做JSON字段提取语法和可读性都比一层层dict取值好很多。pip install jmespathimport jmespath body resp.json() # 验证登录成功后返回的token非空 token jmespath.search(data.token, body) assert token, token不应为空 # 验证用户信息里的手机号脱敏正确 username jmespath.search(data.user.username, body) assert username admin # 验证列表接口返回的数量和财务小计 total jmespath.search(data.page.total, body) assert total 10jmespath的表达能力比直接body[data][user][username]强得多遇到中间某个字段不存在时前者返回None后者直接抛KeyError。配合断言日志定位问题非常快。5.4 第四层数据库校验接口返回成功业务code也是0但数据库里没插入记录——这种Bug在接口层测不出来必须在数据库层加断言。比如测试注册接口注册成功后查一下数据库确认用户记录真的存在import pymysql import pytest pytest.fixture(scopesession) def db_conn(env_config): db_conf env_config[db] conn pymysql.connect( hostdb_conf[host], portdb_conf[port], userdb_conf[user], passworddb_conf[password], databasedb_conf[database], charsetutf8mb4, cursorclasspymysql.cursors.DictCursor, ) yield conn conn.close() def test_register_writes_to_db(client, db_conn): username register_user_001 resp client.request(POST, /api/register, json{username: username, password: 123456}) assert resp.json()[code] 0 with db_conn.cursor() as cursor: cursor.execute(SELECT id FROM user WHERE username%s, (username,)) result cursor.fetchone() assert result is not None, 注册成功后用户应存在于数据库数据库断言要克制只在关键写操作上做。每一条用例都去连数据库查一遍跑得慢不说还容易产生额外的维护成本。5.5 团队的断言规范是怎么定的实际项目里不可能每个用例都写四层断言所以我在团队里定了一个最小规范所有用例必须满足否则不允许合入用例类型最低断言要求所有接口HTTP状态码 业务code涉及关键字段的接口校验data里的核心字段是否为空或是否符合预期注册、下单、支付、改密等写操作增加数据库校验列表/分页接口校验返回数量、总数字段与预期是否一致另外有一条硬性要求断言失败信息里必须包含请求地址、请求参数、响应体。否则排查问题的时候只看一句assert 0 1001完全不知道发生了什么。6. 完整实战注册-登录-查询账户-下单的接口链路测试前面讲的都是单点能力这一节把它们串起来做一个真实的接口链路测试注册新用户、登录拿token、查询账户余额、创建订单。6.1 先设计公共请求封装直接把requests.post散落在各个用例里token要手动塞到header里环境地址要拼接非常容易乱。所以我做了一个简单的ApiClient封装。# common/requests_util.py import requests class ApiClient: def __init__(self, base_url): self.session requests.Session() self.base_url base_url.rstrip(/) self.token def set_token(self, token): self.token token self.session.headers.update({Authorization: fBearer {token}}) def request(self, method, path, **kwargs): url self.base_url path kwargs.setdefault(timeout, 10) resp self.session.request(method, url, **kwargs) return resp def get(self, path, **kwargs): return self.request(GET, path, **kwargs) def post(self, path, **kwargs): return self.request(POST, path, **kwargs)这个封装的好处是所有接口的请求都从同一个入口发出token由set_token统一管理超时时间统一兜底。后面要加日志、加重试机制、加请求ID只需要改这一个类。6.2 conftest.py定义client和token环境conftest.py是pytest的“约定大于配置”文件里面的fixture对同目录及子目录下的所有测试用例可见。# testcases/conftest.py import pytest from common.requests_util import ApiClient pytest.fixture(scopesession) def client(env_config): api_client ApiClient(env_config[base_url]) return api_client pytest.fixture(scopemodule) def login_token(client): resp client.post(/api/login, json{username: admin, password: 123456}) body resp.json() assert body[code] 0, f登录失败: {body} token body[data][token] client.set_token(token) return token注意login_token这个fixture的作用域是module意味着同一个测试模块里的多个用例只会执行一次登录。订单相关的模块都依赖它登录只需要发生一次节省整体运行时间。6.3 核心链路用例下单、余额查询# testcases/test_order_flow.py import pytest from common.file_loader import load_yaml_cases order_cases load_yaml_cases(data/order_cases.yaml) pytest.mark.usefixtures(login_token) class TestOrderFlow: pytest.mark.parametrize(case, order_cases, idslambda c: c[name]) def test_create_order(self, client, case): resp client.post(/api/order, jsoncase[payload]) body resp.json() assert body[code] case[expect][code] assert body[msg] case[expect][msg] if body[code] 0: assert jmespath.search(data.order_id, body), 下单成功应返回订单号 def test_query_balance(self, client): resp client.get(/api/account/balance) body resp.json() assert body[code] 0 assert balance in body[data], 查询余额应返回balance字段 def test_balance_after_order(self, client): 下单成功后余额应减少对应金额 before_resp client.get(/api/account/balance) balance_before before_resp.json()[data][balance] order_resp client.post(/api/order, json{ sku_id: 1001, quantity: 1, address_id: 10, }) assert order_resp.json()[code] 0 amount order_resp.json()[data][pay_amount] after_resp client.get(/api/account/balance) balance_after after_resp.json()[data][balance] assert balance_before - balance_after amounttest_balance_after_order里就用了业务断言不只看下单是否成功还校验了下单后余额真的减少了对应的支付金额并且用减法来避开了浮点精度的干扰。6.4 pytest.ini 配置与报告产出最后在项目根目录建pytest.ini统一配置pytest的行为[pytest] addopts -v --tbshort --htmlreport/report.html --self-contained-html --reruns 2 --reruns-delay 1 testpaths testcases--reruns 2 --reruns-delay 1是pytest-rerunfailures插件的参数允许失败的用例重跑2次中间隔1秒对付偶发性的网络波动非常有用。跑完执行pytest --env test报告自动生成到report/report.htmlHTML是自包含的可以直接发给团队其他人看。6.5 运行时的意外情况第一次跑这套实战用例的时候我遇到过两个典型的坑。一个是token失效问题。登录获取的token有效期可能只有30分钟用例跑了20分钟之后后面的用例突然全部401。后来我在ApiClient的request方法里加了一个401自动重新登录的兜底逻辑token快过期的问题才算解决。另一个是测试数据污染。比如订单测试用例里的sku_id1001在下单之后库存会减少第二次跑同一套用例时库存不足导致失败。解决办法是测试数据使用专门构造的数据或者在用例里用随机数据让每次执行都是独立的数据环境。7. 落地过程中踩过的坑和现在的最终建议这套自动化框架在团队里跑了将近一年从最初的几十条用例长到六百多条。回顾整个过程有几个坑是几乎每个团队都会踩的写出来供你参考。7.1 数据隔离测试数据不能用一套否则用例互相影响早期我们把测试数据和正式测试环境的数据混在一起导致用例之间互相干扰。比如一个用例删除了用户“test_001”另一个用例又拿“test_001”去登录结果第一条用例通过、第二条用例失败跑完整个回归到处是偶发失败的用例。后来改成每个测试用例使用独立的、随机化的数据比如用户名加上时间戳import time def generate_username(prefixuser): return f{prefix}_{int(time.time() * 1000)}虽然用例里多了几行代码但用例之间彻底隔离了跑100次不再出现因为数据冲突导致的偶发失败。7.2 断言失败信息必须带全上下文早期我们的断言就是一行assert body[code] 0失败之后只能看到左右两个值完全不知道是哪个接口、传了什么参数、响应长什么样。后来我写了一个统一的断言辅助函数失败时自动输出完整上下文def assert_code(body, expected_code, *, request_info): if body.get(code) ! expected_code: raise AssertionError( f业务code不匹配, 期望: {expected_code}, 实际: {body.get(code)}, fmsg: {body.get(msg)}, 请求: {request_info} )排查问题的效率立刻提升了一大截。7.3 不要为了自动化而自动化用例要能衡量价值我见过团队把接口自动化用例数做到几千条但覆盖率、发现问题数都很低。因为很多用例是把同一个接口的同一个场景复制了几份只是数据稍微变了一下本质上没有增加覆盖。更好的做法是每一条用例都要能回答“它在验证什么业务规则”。如果一个问题只有手工能发现、自动化覆盖不到那说明团队应该先补测试数据造数能力而不是单纯堆用例数量。7.4 环境变量和敏感信息不要写进代码库数据库密码、测试环境的密钥这些信息直接写进YAML配置并提交到Git仓库是非常危险的做法。团队成员离职、仓库权限收窄、甚至仓库被clone出来密码就泄露了。推荐的做法是配置值支持环境变量覆盖。比如YAML里写password: ${DB_PASSWORD}读取时通过os.environ替换。这样代码库是安全的每个运行环境只需要配置自己的环境变量。7.5 测试数据文件也是代码需要评审和维护数据驱动测试让数据文件成为测试代码的一部分它和代码一样需要评审、需要版本管理、需要清理。我看到过项目里data目录下有一堆没人维护的旧数据文件里面存着已经下线接口的用例跑的时候全是失败后来直接把整个目录废弃了。建议数据文件命名和对应测试模块保持一致用例清理时同步清理数据旧接口下线后数据文件也要删除。一个一直失败的用例比没有用例更伤团队信心。做接口自动化测试参数化、数据驱动、断言这三块能力到位工程质量自然就出来了。工具层面用Postman调试单个接口没有问题但整个回归体系还是需要一套像上面这样可维护的代码工程。把它落地到自己的团队里配好数据隔离、配置管理和日志上下文你会发现接口自动化真正能帮你节省大量手工回归时间并且能在发版前稳稳守住核心业务。
返回列表