news 2026/9/2 19:31:00

Pytest与Requests接口自动化测试框架搭建实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pytest与Requests接口自动化测试框架搭建实战

Pytest 和 Requests 组合做接口自动化测试,是目前 Python 后端测试里最常见、也最接近“成本低、见效快”这个目标的方案。这套框架解决的核心问题很直接:把业务接口从手工验证变成脚本回归,把重复的请求、断言、结果收集和报告展示做成一套可以重复跑的结构,而不是散落一地的临时脚本。如果你刚接触接口自动化测试,或者想从 Postman 手工点选往自动化方向过渡,这篇内容会按零基础可落地的顺序,拆清环境准备、用例编写、公共封装、批量执行和常见问题排查。

看到“框架搭建”四个字不用紧张,Pytest + Requests 的最小可用形态其实非常简单:一个测试目录、几个 test_ 开头的函数、一个发请求的公共封装,就能跑起来。所谓框架化,只是随着接口数量变多,把重复的请求逻辑、断言逻辑、数据准备和结果收集逐步收拢到公共层。关键在于先有一条能稳定跑通的链路,再慢慢加东西。

下面按实际落地顺序拆,从环境准备开始,最后到批量执行和排坑。

1. 先想清楚:Pytest + Requests 解决什么问题

1.1 先把两个工具的分工拆开

Requests 是 Python 的 HTTP 客户端库,只负责一件事:发送 HTTP 请求并接收响应。你在代码里写requests.get(url)requests.post(url, json=data),它会帮你处理 URL 拼接、请求头、请求体、Cookie、超时、SSL 校验这些底层细节。它本身没有测试能力,不会帮你统计多少条用例通过、失败,也不负责生成报告。

Pytest 是测试框架,负责用例的发现和组织。它会按规则找到名字以 test_ 开头的函数或文件,按顺序或分组执行,把断言失败的信息收集起来,最后输出汇总结果。它还提供 fixture、参数化、标记、插件等机制,用来解决用例复用、数据驱动和运行控制。

所以 Pytest + Requests 的本质是两条线:Requests 负责“怎么发请求”,Pytest 负责“什么时候执行、执行结果怎么判断、失败了怎么反馈”。理解这个分工后,后面所有框架设计都围绕它展开,不会跑偏。

1.2 适合哪些场景,不适合哪些场景

适合的场景:

  • 后端 RESTful API 的功能回归测试。比如新增了一个订单接口,要求不影响旧的下单流程。
  • 多环境接口检查。开发环境、测试环境、预发环境,同一套用例换 base_url 跑一遍。
  • 数据驱动的接口测试。同一个登录接口要验几十组账号和预期结果。
  • 接口层级的前置校验。UI 自动化跑之前,先用接口准备测试数据,或者先用接口做冒烟。

不适合的场景:

  • 纯 UI 自动化。按钮点击、页面元素、浏览器兼容这些,应该交给 Selenium 或 Playwright。
  • 高并发压测。Requests 是同步请求,会阻塞等待响应,压测应该用 Locust、JMeter 这类专门工具。
  • 需要很复杂协议模拟的场景。gRPC、WebSocket、MQ 这类场景,Requests 不是最合适的选择。

这个边界不是说不可以,而是不划算。接口自动化的核心价值是快速回归和拦截低级问题,不是替代压测工具,也不是替代 UI 测试。把边界认清楚,后面做框架设计才不会越做越重。

2. 环境准备:从一个最小可运行用例开始

2.1 环境检查和依赖安装

先从 Python 3.8 以上版本开始。当前主流开发环境基本都在 3.9 到 3.12 之间,Requests 和 Pytest 对这几个版本的兼容都很好。如果机器上还没装 Python,直接装官网的稳定版即可,不用刻意装老版本。

项目目录建议单独建一个 venv,避免依赖和系统环境互相干扰。命令行操作大概是这样:

mkdir api_test cd api_test python -m venv venv

Windows 下激活虚拟环境:

venv\Scripts\activate

macOS 或 Linux 下激活:

source venv/bin/activate

然后安装核心库和辅助库:

pip install requests pytest pytest-html pytest-rerunfailures

如果想用并发执行,可以装 pytest-xdist;想用 Allure 报告,装 allure-pytest。这一步先装三个就够,后面用到再补。

装完后验证:

pytest --version python -c "import requests; print(requests.__version__)"

能看到版本号输出,说明环境没问题。开发机只要有一个干净的独立目录,后面所有依赖都有记录。

2.2 第一个 pytest 用例

在 api_test 目录下新建一个文件,名字叫 test_smoke.py:

def test_add(): assert 1 + 1 == 2 def test_sub(): assert 3 - 1 == 2

然后执行:

pytest -v test_smoke.py

-v会打印每条用例的执行结果,看到 test_add 和 test_sub 都 PASSED,Pytest 就正常工作了。之所以用 test_ 开头,是因为 Pytest 默认的用例发现规则就是匹配 test_ 开头的函数、类和方法。文件名也建议用 test_ 开头,目录命名也可以统一用 testcase 风格。

2.3 加一个真正发 HTTP 请求的用例

接下来给 Requests 一个真正的工作。示例用公开测试服务,网上常见的接口测试服务是 httpbin.org。但办公环境里建议先确认网络可达性,很多公司内网访问外网会不稳定,还会遇到网络策略限制。实际落地时最好直接换成自己公司的开发或测试环境。

import requests def test_get_request(): resp = requests.get("https://httpbin.org/get", timeout=10) assert resp.status_code == 200

执行:

pytest -v test_smoke.py

如果看到 PASSED,说明 Requests 已经能在当前环境里正常发起 HTTP 请求。

这里有两个细节容易被忽略:

  1. timeout=10是必需的。如果不写,Requests 会一直等待响应,遇到服务端不返回的情况,用例就会长时间挂住,很难排查。
  2. 不能只看状态码是 200 就认为通过了。很多接口在 200 状态下仍然会返回业务错误,比如{"code": 5001, "message": "参数错误"}。所以断言要分层,先验状态码,再验业务字段。

3. 围绕 Requests 做基础封装:session、超时、重试和统一断言

3.1 为什么不能在每个用例里直接发请求

如果只有几个用例,直接在用例里requests.get完全没问题。但项目慢慢变大后,问题就出来了:

  • 每个用例都要写请求头,token 一变,所有用例都要改。
  • 每个用例都要处理超时、重试、日志,代码重复。
  • 测试环境切换时,base_url 到处散落。
  • 接口请求日志不统一,出了问题不知道请求到底发出没有。

所以框架化的第一个动作,就是把 HTTP 请求收拢成一个公共封装。最小封装可以是一个函数,也可以是类。我更建议用类,因为后续要扩展 session、认证、公共参数,类的扩展性更好。

3.2 用 Session 复用连接和认证信息

requests.Session很重要。它会在同一实例内复用 TCP 连接,自动管理 Cookie,还能统一设置请求头。比如登录后拿到 token,可以存在 session.headers 里,后续请求自动带上。

import requests from requests.adapters import HTTPAdapter class ApiClient: def __init__(self, base_url, token=None): self.base_url = base_url self.session = requests.Session() # 有 token 就统一加到请求头 if token: self.session.headers.update({"Authorization": f"Bearer {token}"}) # 配置连接层重试,只针对连接错误和读超时,不是针对 429 adapter = HTTPAdapter(max_retries=2) self.session.mount("http://", adapter) self.session.mount("https://", adapter) def get(self, path, params=None): url = self.base_url + path return self.session.get(url, params=params, timeout=10) def post(self, path, json=None): url = self.base_url + path return self.session.post(url, json=json, timeout=10)

这里有一个很容易踩的坑:HTTPAdapter(max_retries=2)负责的是连接失败或连接池读失败时的自动重试,它不会把 HTTP 429 或 500 这类响应状态码当作失败去重试。很多新手以为设置 max_retries 后就能解决限流导致的 429,实际不会。429 需要单独做状态码层面的重试策略。

3.3 统一超时和异常处理

封装里必须考虑两个问题。

第一,timeout=10只认一个超时值,其实可以传一个元组(连接超时, 读取超时)

timeout=(5, 15)

5 秒内连不上就失败,连上后 15 秒内读不到数据就失败。这个比只写一个数字更精细,建议在自有项目里用。

第二,请求异常要转成清晰的信息。Requests 在连接失败时会抛出requests.exceptions.ConnectionError,超时抛出requests.exceptions.Timeout,如果不处理,Pytest 会把它

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 19:25:07

余晖烁烁同人插画教程:从台词到夕阳氛围的完整绘制流程

绘制一张余晖烁烁的同人插画时,最难的不是把角色画得像,而是让画面里的夕阳、表情和构图共同说出那句台词:“Can I get a kiss, sunset?” 这句台词没有交代动作,也没有给出场景,但信息量很大:它…

作者头像 李华
网站建设 2026/9/2 19:24:15

火王智能灶值得装吗?智能关火、语音控制、一级能效全面拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 19:22:29

5G如何驱动AI应用落地:从网络切片到边缘计算的工程实践

最近一则来自英国电信高管的公开警告,在通信圈和 AI 圈几乎同步刷屏:“5G 升级太慢,英国可能输掉 AI 竞赛。”这句话看似是英国本土的产业焦虑,但背后其实牵出了一个全球开发者都在关心的问题——5G 网络和 AI 应用之间到底是什么…

作者头像 李华
网站建设 2026/9/2 19:19:24

Python快速GUI开发:Gradio与Streamlit实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 19:12:53

AI API成本治理全链路:以Claude API为例的监控与优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 19:11:28

DeepSeek Harness插件开发实战:从环境搭建到企业级落地

DeepSeek Harness 插件开发,是不少 AI 应用团队在把 DeepSeek 模型能力沉淀成可复用业务模块时,重点关注的工程方向之一。早期团队通常直接通过 API 调用模型,把返回结果拼进业务界面,这种方式在演示阶段没有问题;可一…

作者头像 李华