Pytest+requests进行接口自动化测试1.0(基础知识 + 测试用例 + request库)

发布于:2025-09-09 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、接口自动化测试基础知识

1.接口自动化测试介绍

接口自动化测试,就是通过编写代码或使用工具,自动发送请求到系统的接口(API),并自动验证返回结果是否符合预期的过程。
它属于功能自动化测试的一种,主要关注“系统之间如何通信”,而不是用户界面(UI)。

2.下载常用Python接口自动化相关库

工具/库 作用
requests 发送HTTP请求(GET/POST等请求)
pytest 核心测试框架,编写和运行测试用例
jsonpath-ng 从JSON中提取数据,用于解析复杂JSON响应
PyYAML 用YAML文件管理测试数据(数据与代码分离),用于读取YAML格式的测试用例或配置
allure-pytest 生成可视化测试报告,配合Allure命令行可生成高级报告
python-dotenv 管理不同环境的配置(如测试服、生产服,进行环境隔离),可用于 .env 文件管理环境变量
pytest-html 生成基础HTML报告,快速出报告
requests-mock “模拟请求”的库,用于单元测试,对进阶测试很有用

1)使用清华大学镜像源安装命令

清华大学 pip 镜像地址:https://pypi.tuna.tsinghua.edu.cn/simple/

2)cmd 一行安装所有库

pip install requests pytest pytest-html allure-pytest PyYAML jsonpath-ng python-dotenv requests-mock -i https://pypi.tuna.tsinghua.edu.cn/simple/

安装好后会有类似“Successfully installed …”的提示信息

3)可以逐个cmd运行以下命令,找到安装位置安装信息

pip show requests
pip show pytest
pip show jsonpath-ng
pip show PyYAML
pip show allure-pytest
pip show python-dotenv
  • 举例

在这里插入图片描述

3.接口文档

接口文档可以找开发要,我们部门的开发是使用Apifox的,所以我直接在上面下载接口文档

在这里插入图片描述

此处我选择了Markdown格式下载,下载后使用Typora打开可以导出pdf格式的接口文档

在这里插入图片描述

接口文档内容示例:重点包含URL,接口名,接口路径,请求方法,请求参数,返回结果

在这里插入图片描述

在这里插入图片描述

4.Postman(Apifox)进行简单的接口调试

在把一个接口写到我们的测试代码前,我们要在Postman中先进行调试,调试成功再写入代码

在这里插入图片描述

二. 如何设计接口测试用例

1. 单接口测试用例(一个接口写5.6条即可)

  • 目标:

验证单个接口在各种输入条件下的功能正确性、参数处理能力和异常处理机制

  • 设计思路:

基于接口文档(如 Swagger/OpenAPI)分析请求方法、路径、参数、返回值。
覆盖正常场景、边界值、异常输入、必填项缺失等。

  • 测试用例设计方法:
测试用例设计方法 设计思路 预期结果
正向测试用例 1.覆盖所有必选参数 2.组合非必填参数 3.边界值测试 查看返回数据
反向测试用例 1.参数缺失 2. 参数为空 3.参数类型错误 4.参数超长 5.枚举值非法 查看返回数据

补充:枚举值非法 如:status: “pending2”(只允许 pending/approved)

2. 业务逻辑接口测试用例

  • 目标:

验证多个接口串联后的业务流程完整性,模拟真实用户操作路径

  • 常见业务场景:

用户注册 → 登录 → 获取个人信息
添加商品到购物车 → 创建订单 → 支付 → 查看订单状态
发布文章 → 审核通过 → 前端展示

  • 设计思路:

梳理业务流程图(流程图或时序图)
按照“前置条件 → 操作步骤 → 预期结果”组织用例
使用自动化工具(如 Postman Collections + Tests 脚本)实现链式调用

  • 测试用例设计方法:
测试用例设计方法 设计思路 预期结果
正向测试用例 正常进行全流程业务 查看返回数据
反向测试用例 上下接口之间有参数关联,某一个环节出现问题,该接口则请求失败 查看返回数据

示例:电商下单流程
步骤 接口 说明
1 POST /login 获取 token
2 GET /products 查询商品列表
3 POST /cart 添加商品到购物车
4 POST /order 创建订单
5 POST /pay 支付订单
6 GET /order/{id} 查询订单状态是否为“已支付”

设计电商下单流程测试用例:

用例编号 场景 预期结果
TC101 正常下单支付全流程 所有接口调用成功,订单状态为“已支付”
TC102 未登录下单 第一步无 token,应返回 401
TC103 购物车为空创建订单 应提示“购物车为空”
TC104 重复支付 第二次支付应失败,防止重复扣款
TC105 库存不足 下单时库存 <1,应提示“库存不足”

3. 接口安全性(一般项目安全性校验较少)

  • 目标:

确保接口不会被恶意利用,防止数据泄露、越权访问、注入攻击等安全风险。

  • 常见安全测试点:
安全维度 测试内容 示例
认证与授权 是否校验 token?是否存在未授权访问? 用 A 用户 token 访问 B 用户数据,应拒绝
越权访问 普通用户能否操作管理员接口? /admin/deleteUser 普通用户调用应返回 403
注入攻击 是否防范 SQL/XSS/命令注入? 参数传 ’ OR ‘1’='1,检查是否执行异常 SQL
重放攻击 相同请求重复发送是否生效? 同一支付请求发两次,第二次应失败
限流控制 是否防止暴力破解? 登录接口连续失败 5 次应锁定账户或限流
敏感信息泄露 返回数据是否包含密码、身份证等? GET /user 不应返回明文密码或银行卡号
数据加密 传输是否使用 HTTPS?敏感字段是否加密? 检查是否强制 HTTPS,密码是否哈希存储
  • 安全测试用例示例:
用例编号 安全测试场景 预期结果
SEC001 未登录访问需认证接口 返回 401 Unauthorized
SEC002 用户A访问用户B的数据 返回 403 Forbidden
SEC003 SQL注入测试(user_id=1’ OR ‘1’='1) 返回 400 或正常过滤,不返回数据库错误
SEC004 敏感字段加密 返回的手机号、邮箱应脱敏(如 138****1234)
SEC005 登录接口限流 连续输错5次密码,第6次提示“账户锁定”

三. requests库

Python中一个非常流行的HTTP请求库,用于发送HTTP请求,它提供了丰富的功能,如会话、参数传递、表单提交等,同时还支持SSL证书验证。

1. 安装与导入

  • 使用命令安装requests库
pip install requests
  • 脚本中导入requests模块
import requests

2. 基本用法 GET,POST

  • 查看get,post代码,我们可以看到需要传入的参数

在这里插入图片描述

  • 准备参数
--  GET
url = "http://127.0.0.1:8787/coupApply/cms/goodsList"
headers = {"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"}
params = {
    "msgType": "getHandsetListOfCust",
    "page": 1,
    "size": 20
}


--  POST
url = "http://127.0.0.1:8787/dar/user/login"
headers = {"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"}   # 字典类型请求头
headers = {"application/json;charset=UTF-8"}
data = {
    "user_name": "test01",
    "passwd": "admin123"
}
  1. 发送GET请求
requests= requests.get(url="http://127.0.0.1:8787/coupApply/cms/goodsList",headers=headers,params=params)

print(response.status_code)    ----- 打印响应的状态码
print(response.text)           ----- 打印响应的内容(文本格式,字符串)
print(response.json())         ----- (json格式,字典)
print(response.content())      ----- (二进制格式)
  1. 发送POST请求
response = requests.post('http://127.0.0.1:8787/dar/user/login', headers=headers,data=data, json= json)

print(response.text.encode('').decode(''))    ----- 输出方式和get一样,如果打印有乱码,转换格式

注意:请求头不一样,使用的参数不一样
data表单格式 --------- headers = {“Content-Type”:“application/x-www-form-urlencoded;charset=UTF-8”}
json格式 ----- headers = {“application/json;charset=UTF-8”}

  • 运行结果

在这里插入图片描述

注意: 运行结果为{ " " }的是字符串格式, { ’ ’ }为字典格式

  • GET ,POST,PUT,DELETE 的区别
import requests

---- 获取用户
response = requests.get("http://api.example.com/users/1")

---- 创建用户
response = requests.post("http://api.example.com/users", json={"name": "王五"})

---- 更新用户(全量)
response = requests.put("http://api.example.com/users/1", json={"name": "赵六", "age": 28})

---- 删除用户
response = requests.delete("http://api.example.com/users/1")

3. 高级用法

  1. 会话对象:使用 requests.Session() 创建会话对象,可以保持会话状态(如 Cookie)
session = requests.Session()
response = session.request(method='get',url=url,params=data,headers=headers)

常见用法: 在做接口测试时,很多系统需要先登录,然后后续操作(如查看个人信息、下单)才能成功。
使用 Session 可以自动保存 Cookie,像浏览器一样保持“登录状态”。

  1. 超时设置:通过 timeout 参数设置请求超时时间
response = requests.get('http://example.com', timeout=5)

常见用法:网络请求可能会因为服务器慢或网络问题一直“卡住”。设置超时可以避免程序假死。

  1. 自定义头部:通过 headers 参数设置请求头部
headers = {'User-Agent': 'My User Agent 1.0'}
response = requests.get('http://example.com', headers=headers)

常见用法:有些接口会校验请求头(如 User-Agent、Authorization、Content-Type),否则拒绝访问。

  1. 获取接口的Cookie:通过requests.utils.dict_from_cookiejar() 获取返回的 Cookie
from requests import utils
from urllib.parse import urlparse

session = requests.Session()
response = session.request(method='post',url=url1,data=data,headers=headers)
requests.utils.dict_from_cookiejar(response.cookies)    --- 是 requests 官方提供的工具,能正确处理复杂的 CookieJar 对象

在这里插入图片描述

常见用法:登录后获取 Cookie,并用于后续请求。

获取Cookie的导入语句讲解

  1. requests.utils 是 Python 第三方库 requests 提供的一个工具模块,轻松处理Cookie、编码、重试等
from requests import utils
  • 最常用的几个功能:
函数 作用 使用场景
dict_from_cookiejar() 把 CookieJar 对象转成普通字典 获取响应中的 Cookie 并保存
cookiejar_from_dict() 把字典转成 CookieJar 对象 恢复 Cookie 用于后续请求
requote_uri() 安全地对 URL 进行编码 处理中文、特殊字符的 URL
get_encodings_from_content() 从 HTML 内容中提取编码 爬虫中判断网页编码
  • 实际例子:登录后获取 Cookie 并转为字典(常用)
import requests
from requests import utils

# 发送登录请求
response = requests.post(
    'https://example.com/login',
    data={'username': 'test', 'password': '123456'}
)

# 获取服务器返回的 Cookie,并转为字典(方便查看或存储)
cookies_dict = utils.dict_from_cookiejar(response.cookies)
print(cookies_dict)
# 输出示例:{'sessionid': 'abc123xyz', 'user': 'test'}
  1. urlparse 是 Python 标准库 urllib.parse 中的一个核心函数,用于解析 URL 的各个组成部分

它可以把一个完整的 URL 拆解成协议、域名、端口、路径、参数等部分,非常适用于接口测试、路由判断、安全校验等场景。

  • 实际用途举例:
1. 判断是否是 HTTPS(安全协议)
 if parsed.scheme == 'https':
    print("使用了加密传输,安全!")
    
2. 提取 API 域名,用于统一管理
 base_url = f"{parsed.scheme}://{parsed.hostname}"
 print(base_url)  # https://example.com
 
3. 校验请求是否发往合法域名(防止误调用)
 allowed_hosts = ['api.example.com', 'test.example.com']
 if parsed.hostname not in allowed_hosts:
     raise ValueError("不允许请求该域名!")
  • 所有高级用法

在这里插入图片描述

4. 封装post,get请求

  • 为什么要封装?
不封装 封装后
重复写 headers、timeout 一次配置,全局生效
手动处理 token 自动更新认证信息
出错难排查 统一日志 + 异常处理
难以复用 可被多个测试用例调用
无法扩展 易于添加新功能
  • 示例:简单封装
---       -*- coding:utf-8 -*-   防止编码格式报错
import requests
class SendRequest:
    """
    封装接口的请求
    """
    def __init__(self):
        pass
    def get(self,url,params,header):
        """
        封装get请求
        :param url:  请求地址
        :param params:   请求参数
        :param header:   请求头
        :return:
        """
        if header is None:
            res = requests.get(url,params=params)
        else:
            res = requests.get(url,params=params,headers=header)
        return res.json()

    def post(self,url,data,header):
        """
        封装post请求
        :param url:   请求地址
        :param data:   请求参数
        :param header:   请求头
        :return:
        """
        if header is None:
            res = requests.post(url,data,verify=False) --- 直接传,post参数需要进行data和json的判断
                                      --- 忽略https证书校验
        else:
            res = requests.post(url,data,headers=header,verify=False)
        return res.json()

    def put(self):
        pass
    def delete(self):
        pass

    def run_main(self,url,data,header,method):    --- 定义主函数
        """
        接口请求主函数
        :param url:请求地址
        :param data:请求参数
        :param header:请求头
        :param method:请求方法
        :return:
        """
        res = None         --- 定义自身函数
        if method.upper() == 'GET':          --- 把传入参数转成大写
            res = self.get(url,data,header)
        elif method.upper() == 'POST':
            res = self.post(url,data,header)
        else:
            print('暂时只支持“get、post请求')
        return res

if __name__ == '__main__':
    url = "http://127.0.0.1:8787/coupApply/cms/goodsList"
    headers = {"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"}
    params = {
        "msgType": "getHandsetListOfCust",
        "page": 1,
        "size": 20
    }
    method = 'GET'
    send = SendRequest()
    result = send.run_main(url=url,data=params,header=headers,method=method)
    print(result)

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到