基于 Python 自动化接口测试(踩坑与实践)

news2025/1/9 15:55:27

文档:基于 Python 的自动化接口测试


在这里插入图片描述

目录

  1. 背景
  2. 问题描述与解决思路
  3. 核心代码
  4. 修改点及其详细解释
  5. 最终测试结果
  6. 后续优化建议

1. 问题背景

本项目旨在使用 Python 模拟浏览器的请求行为,测试文章分页接口的可用性。测试目标接口如下:

bash

coderboots
http://localhost:8081/api/article/page

接口需要携带与浏览器完全一致的请求头和 Cookies,同时需支持分页参数(如 currentsize)。

重点是, 使用postman和浏览器都可以正常测试,但是使用python脚本测试失败。 —遇到网络问题, 一定要记得思考是否是代理问题。


2. 问题描述与解决思路

问题描述

  1. 初次尝试时,脚本请求失败,返回 502 Bad Gateway 错误。
  2. 原因分析表明,requests 库默认继承系统代理配置,而代理拦截或错误转发了请求。
  3. 此外,初始代码未完全复制浏览器的 Headers 和 Cookies。

解决思路

  1. 禁用代理:显式设置 proxiesNone,避免系统代理干扰。
  2. 完整复制 Headers 和 Cookies:确保请求与浏览器的行为一致。
  3. 日志改进:详细记录请求 URL、Headers 和响应信息,便于调试和问题定位。
  4. 重试机制:为网络不稳定的情况添加重试逻辑,提高脚本健壮性。

3. 核心代码

以下是经过优化的测试脚本:

python


coderboots
import requests
import logging
import time

class ArticleApiTest:
    def __init__(self):
        self.base_url = "http://localhost:8081/api/article"
        
        # 设置请求头,确保与浏览器一致(后面证明只需要修改代理即可)
        self.headers = {

        }
        
        # 设置Cookies
        self.cookies = {
          
        }
        
        # 创建 session 并禁用代理
        self.session = requests.Session()
        self.session.headers.update(self.headers)
        self.session.cookies.update(self.cookies)
        self.session.proxies = {'http': None, 'https': None}
        
        # 设置超时时间
        self.timeout = 10
        
        # 设置日志记录
        logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
        self.logger = logging.getLogger(__name__)

    def get_page(self, current=1, size=10):
        """发送分页请求"""
        url = f"{self.base_url}/page"
        params = {'current': current, 'size': size}
        
        try:
            # 发送请求
            response = self.session.get(url, params=params, timeout=self.timeout, verify=False)
            
            # 记录日志
            self.logger.info(f"Request URL: {response.url}")
            self.logger.info(f"Response Status: {response.status_code}")
            
            if response.status_code == 200:
                self.logger.info("Request successful")
                self.logger.info(f"Response Data: {response.json()}")
            else:
                self.logger.error(f"Request failed with status code: {response.status_code}")
            
            return response
        except requests.RequestException as e:
            self.logger.error(f"Request failed: {str(e)}")
            return None

def main():
    tester = ArticleApiTest()
    print("开始测试...")
    response = tester.get_page()
    if response and response.status_code == 200:
        print("✅ 测试成功")
    else:
        print("❌ 测试失败")

if __name__ == "__main__":
    main()

4. 修改点及详细解释

修改点 1:禁用代理 --重点和关键

  • 原因:初次运行时,系统代理干扰了请求,导致 502 Bad Gateway 错误。
  • 解决方法:在 requests.Session 中添加 proxies 参数,将 httphttps 显式设置为 None

代码:

python


coderboots
self.session.proxies = {'http': None, 'https': None}

修改点 2:完整的 Headers 和 Cookies

  • 原因:部分请求头(如 User-Agentsec-ch-ua)以及 Cookies 在初始代码中未设置,导致服务器未正确识别请求。(由于本次后端其实没有做特别的鉴权,所以这里其实设置为空也可以正常访问)
  • 解决方法:复制浏览器中的完整 Headers 和 Cookies 并在 requests.Session 中更新。

代码:

python


coderboots
self.headers = {
    # 浏览器请求头
}
self.cookies = {
    # 浏览器 Cookies
}

修改点 3:日志记录

  • 原因:初始代码缺乏详细的日志,不利于调试。
  • 解决方法:添加请求 URL、Headers 和响应状态的详细日志记录。

代码:

python


coderboots
self.logger.info(f"Request URL: {response.url}")
self.logger.info(f"Response Status: {response.status_code}")
self.logger.info(f"Response Data: {response.json()}")

5. 最终测试结果

运行脚本后,成功返回分页数据,日志记录如下:

yaml


coderboots
2025-01-08 01:42:21,175 - INFO - Request URL: http://localhost:8081/api/article/page?current=1&size=10
2025-01-08 01:42:21,175 - INFO - Response Status: 200
2025-01-08 01:42:21,176 - INFO - Request successful
2025-01-08 01:42:21,176 - INFO - Response Data: {...}
✅ 测试成功

6. 后续优化建议(略)

  1. 动态 CSRF Token 支持
    • 如果接口需要动态 Token,可以在发送请求前自动提取并添加到 Headers。
  2. 重试机制
    • 针对请求失败的情况(如网络不稳定或服务器错误),增加智能重试机制。
  3. 异步请求
    • 如果需要测试多个接口,可以使用 asyncio 实现异步请求,提高效率。
  4. 自动化集成
    • 将脚本集成到 CI/CD 管道中,定期验证接口的可用性。

通过上述改进,该脚本现已具备稳定性、可调试性和一致性,能够准确模拟浏览器请求行为并测试目标接口。

最后给一个好用的模版:

修改template 为你的模块名称即可

import requests
import json
from colorama import init, Fore, Style
import os

# 初始化colorama
init()

# 禁用系统代理
os.environ['no_proxy'] = '*'


class TemplateApiTest:
    def __init__(self, base_url="http://localhost:8081/api"):
        self.base_url = base_url
        self.headers = {
            "Content-Type": "application/json"
        }

    def print_response(self, api_name, response):
        """格式化打印响应结果"""
        print(f"\n{Fore.CYAN}测试接口:{Style.RESET_ALL} {api_name}")
        print(f"{Fore.CYAN}请求URL:{Style.RESET_ALL} {response.url}")
        print(f"{Fore.CYAN}状态码:{Style.RESET_ALL} {response.status_code}")

        if response.status_code == 200:
            print(f"{Fore.GREEN}响应结果:{Style.RESET_ALL}")
            try:
                formatted_json = json.dumps(response.json(), ensure_ascii=False, indent=2)
                print(formatted_json)
            except:
                print(response.text)
        else:
            print(f"{Fore.RED}错误响应:{Style.RESET_ALL}")
            print(response.text)
        print("-" * 80)

    def test_get_page(self):
        """测试分页查询模板"""
        params = {
            "current": 1,
            "size": 10,
            "category": "通用模板"
        }
        response = requests.get(
            f"{self.base_url}/template/page",
            params=params,
            headers=self.headers
        )
        self.print_response("分页查询模板", response)

    def test_get_template_by_id(self):
        """测试根据ID获取模板"""
        template_id = 1
        response = requests.get(
            f"{self.base_url}/template/{template_id}",
            headers=self.headers
        )
        self.print_response(f"获取模板(ID: {template_id})", response)

    def test_save_template(self):
        """测试保存新模板"""
        template_data = {
            "name": "测试模板",
            "content": "这是一个测试模板的内容",
            "category": "通用模板",
            "description": "用于测试的模板"
        }
        response = requests.post(
            f"{self.base_url}/template",
            headers=self.headers,
            data=json.dumps(template_data)
        )
        self.print_response("创建新模板", response)

    def test_update_template(self):
        """测试更新模板"""
        template_data = {
            "id": 1,
            "name": "更新后的测试模板",
            "content": "这是更新后的测试模板内容",
            "category": "通用模板",
            "description": "已更新的测试模板"
        }
        response = requests.put(
            f"{self.base_url}/template",
            headers=self.headers,
            data=json.dumps(template_data)
        )
        self.print_response("更新模板", response)

    def test_delete_template(self):
        """测试删除模板"""
        template_id = 1
        response = requests.delete(
            f"{self.base_url}/template/{template_id}",
            headers=self.headers
        )
        self.print_response(f"删除模板(ID: {template_id})", response)


def main():
    # 创建测试实例
    tester = TemplateApiTest()

    try:
        print(f"\n{Fore.YELLOW}=== 开始测试模板接口 ==={Style.RESET_ALL}")
        tester.test_get_page()
        tester.test_get_template_by_id()
        tester.test_save_template()
        tester.test_update_template()
        tester.test_delete_template()
        print(f"{Fore.YELLOW}=== 模板接口测试完成 ==={Style.RESET_ALL}\n")
    except requests.exceptions.RequestException as e:
        print(f"{Fore.RED}测试过程中发生错误: {e}{Style.RESET_ALL}")


if __name__ == "__main__":
    main()
   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2273875.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单片机-外部中断

中断是指 CPU 在处理某一事件 A 时,发生了另一事件 B,请求 CPU 迅速去处理(中断发生);CPU 暂时停止当前的工作(中断响应), 转去处理事件 B(中断服务);待 CPU 将事件 B 处理完毕后,再回到原来事件 A 被中断的…

vite5.x配置https

旧版的vite直接在config里面配置https:true即可,新版的麻烦一些。 1.准备工作 需要安装openssl 下载地址:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 找到合适的版本安装,配置好环境变量&#x…

Clip Studio Paint 报错:Running on unsupported Os. Clip Studio Paint will close.

问题描述 启动 Clip Studio Paint 报错:Running on unsupported Os. Clip Studio Paint will close. 原因 Clip Studio Paint 锁区,系统是中国大陆的无法使用。 解决方式 打开系统设置 时间和语言- 区域- 区域格式- 简体中文(新加坡&am…

vue2/vue3中使用的富文本编辑器vue-quill

前言: 整理下常用的富文本编辑器工具。 vue3: 实现效果: 实现步骤: 1、安装插件, 编辑器核心插件 vueup/vue-quill yarn add pnpm i npm i cnpm i vueup/vue-quill vueup/vue-quill 2、安装选择性插件 &am…

Vscode 如何使用GitHub Copilot

一、“GitHub Copilot”进行登录 前提必须有github账号,如果没有就注册一个; 系统会提示您输入 GitHub 凭据。单击“登录 GitHub”,然后单击“允许”并输入您的 GitHub 凭据。 登录成功后: 二、 GitHub Copilot功能 1、预测代码 …

docker搭建atlassian-confluence:7.2.0

文章目录 引言I 部署前准备数据库镜像准备自己构建镜像dockerhub第三方镜像II 安装启动容器基础配置(获取服务器ID)授权码获取集群选择设置数据库配置管理员账号引言 准备数据库、镜像启动容器获取服务器ID根据服务器ID等信息,基于atlassian-agent.jar 授权I 部署前准备 数…

通过可穿戴外骨骼,以更灵活的方式操作你的机器人。

今天,我们将介绍一款专为控制 Mercury X1 和 Mercury B1 机械臂而设计的创新外骨骼。这种外骨骼以人类手臂的结构为蓝本,可实现直观和精确的控制。 开发这种外骨骼的动机源于人们对深度学习和机器学习等领域日益增长的兴趣。这些技术使机器人能够自主学习…

Ubuntu更改内核

需求背景: 由于软件需要在较低版本或者指定版本才可以运行 版本: 配置文件: vi /etc/default/grub 启动界面: 可运行版本: 解决方案: 方案1、更改启动顺序 sudo vi /etc/default/grub 方案2、调整启动顺…

maven之插件调试

当使用maven进行项目管理的时候,可能会碰到一些疑难问题。网上资料很少,可能会想着直接调试定位问题。这里以maven-compiler-plugin为例: (1)准备maven-compiler-plugin源码 进入maven 官网-》Maven Plugins-》找到对…

DevToys 专为 Windows 开发者打造的“瑞士军刀”式离线软件

你是否还在为寻找各种在线开发小工具而疲于奔波?**每次要格式化 JSON、比较文本、或者测试正则表达式,都得打开一堆网站,弹窗广告满天飞,严重影响工作效率。想不想要一个“多合一”的离线工具箱,轻松搞定开发中琐碎的日…

INT301 Bio Computation 题型整理

perceptron 设计和计算 1. XOR: 当两个输入值中只有一个为真时,输出为真 2. 3. 5. 6. 7. 2^3 2^n 9. a) 直接test b) 把v≥2 改成 v≥1 10. no, because it cant be separate through only one decision boundary,its not linearlly separable. Backpropagatio…

009:传统计算机视觉之边缘检测

本文为合集收录,欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 本节来看一个利用传统计算机视觉方法来实现图片边缘检测的方法。 什么是边缘检测? 边缘检测是通过一些算法来识别图像中物体之间或者物体与背景之间的边界&…

ffmpeg-avio实战:打开本地文件或者网络直播流dome

使用ffmpeg打开打开本地文件或者网络直播流的一个小dome。流程产靠ffmpeg4.x系列的解码流程-CSDN博客 #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include <libavutil/file.h> #include &l…

Unity Burst详解

【简介】 Burst是Unity的编译优化技术&#xff0c;优化了从C#代码编译成Native代码的过程&#xff0c;经过编译优化后代码有更高的运行效率。 在Unity中使用Burst很简单&#xff0c;在方法或类前加上[BurstCompile]特性即可。在构建时编译代码的步骤&#xff0c;Burst编译器会…

el-table 合并单元格

参考文章&#xff1a;vue3.0 el-table 动态合并单元格 - flyComeOn - 博客园 <el-table :data"tableData" border empty-text"暂无数据" :header-cell-style"{ background: #f5f7fa }" class"parent-table" :span-method"obj…

WebRTC 在视频联网平台中的应用:开启实时通信新篇章

在当今这个以数字化为显著特征的时代浪潮之下&#xff0c;实时通信已然稳稳扎根于人们生活与工作的方方面面&#xff0c;成为了其中不可或缺的关键一环。回首日常生活&#xff0c;远程办公场景中的视频会议让分散各地的团队成员能够跨越地理距离的鸿沟&#xff0c;齐聚一堂共商…

OpenAI CEO 奥特曼发长文《反思》

OpenAI CEO 奥特曼发长文《反思》 --- 引言&#xff1a;从 ChatGPT 到 AGI 的探索 ChatGPT 诞生仅一个多月&#xff0c;如今我们已经过渡到可以进行复杂推理的下一代模型。新年让人们陷入反思&#xff0c;我想分享一些个人想法&#xff0c;谈谈它迄今为止的发展&#xff0c;…

网络空间安全导论期末考试复习题

题型&#xff1a;10个选择题10个大题 1、选择题 简单&#xff0c;记忆书本里的小标题 2、大题&#xff08;较难&#xff09; 网络安全体系的五个层次的内容画公钥密码结合报文鉴别的示意图解释误用入侵检测并画示意图解释隧道技术并画示意图防火墙的作用&#xff0c;防火墙和…

接口测试-postman(使用postman测试接口笔记)

一、设置全局变量 1. 点击右上角设置按钮-》打开管理环境窗口-》选择”全局“-》设置变量名称&#xff0c;初始值和当前值设置一样的&#xff0c;放host放拼接的url&#xff0c;key放鉴权那一串字符&#xff0c;然后保存-》去使用全局变量&#xff0c;用{{变量名称}}形式 二、…

每日一题-两个链表的第一个公共结点

文章目录 两个链表的第一个公共结点问题描述示例说明示例 1示例 2 方法及实现方法描述代码实现 复杂度分析示例运行过程示例 1示例 2 总结备注 两个链表的第一个公共结点 问题描述 给定两个无环的单向链表&#xff0c;找到它们的第一个公共节点。如果没有公共节点&#xff0c…