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

文档:基于 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()
   

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot教程之五十一:Spring Boot – CrudRepository 示例

Spring Boot – CrudRepository 示例 Spring Boot 建立在 Spring 之上,包含 Spring 的所有功能。由于其快速的生产就绪环境,使开发人员能够直接专注于逻辑,而不必费力配置和设置,因此如今它正成为开发人员的最爱。Spring Boot 是…

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…

使用强化学习训练神经网络玩俄罗斯方块

一、说明 在 2024 年暑假假期期间,Tim学习并应用了Q-Learning (一种强化学习形式)来训练神经网络玩简化版的俄罗斯方块游戏。在本文中,我将详细介绍我是如何做到这一点的。我希望这对任何有兴趣将强化学习应用于新领域的人有所帮助…

计算机网络 (32)用户数据报协议UDP

前言 用户数据报协议(UDP,User Datagram Protocol)是计算机网络中的一种重要传输层协议,它提供了无连接的、不可靠的、面向报文的通信服务。 一、基本概念 UDP协议位于传输层,介于应用层和网络层之间。它不像TCP那样提…

如何将 DotNetFramework 项目打包成 NuGet 包并发布

如何将 DotNetFramework 项目打包成 NuGet 包并发布 在软件开发过程中,将项目打包成 NuGet 包并发布到 NuGet 库,可以让其他开发者方便地引用和使用你的项目成果。以下是将 WixWPFWizardBA 项目打包成 NuGet 包并发布的详细步骤: 1. 创建 .n…

解决GitHub上的README.md文件的图片内容不能正常显示问题

一、问题描述 我们将项目推送到GitHub上后,原本在本地编写配置好可展现的相对路径图片内容,到了GitHub上却不能够正常显示图片内容,我们希望能够在GitHub上正常显示图片,如下图所示: 二、问题分析 现状:REA…

如何解决 VS Code 调试时无法查看 std 中变量的问题

在使用 VS Code 调试 C 程序时,我们经常遇到查看 std 容器或字符串变量时只显示一串数字而看不到实际值的情况。这是由于调试器未启用 pretty-printing 功能导致的。为了解决这个问题,可以在 launch.json 中进行配置。 问题描述 在调试 C 程序时&…

安装MySQL的五种方法(Linux系统和Windows系统)

一.在Linux系统中安装MySQL 第一种方法:在线YUM仓库 首先打开MySQL官网首页 www.mysql.com 找到【DOWNLOADS】选项,点击 下拉,找到 【MySQL Community(GPL) Downloads】 在社区版下载页面中,【 MySQL Yum Repository 】链接为在线仓库安装…

基于mybatis-plus历史背景下的多租户平台改造

前言 别误会,本篇【并不是】 要用mybatis-plus自身的多租户方案:在表中加一个tenant_id字段来区分不同的租户数据。并不是的! 而是在假设业务系统已经使用mybatis-plus多数据源的前提下,如何实现业务数据库隔开的多租户系统。 这…

RabbitMQ高级篇之MQ可靠性 数据持久化

文章目录 消息丢失的原因分析内存存储的缺陷如何确保 RabbitMQ 的消息可靠性?数据持久化的三个方面持久化对性能的影响持久化实验验证性能对比Spring AMQP 默认持久化总结 消息丢失的原因分析 RabbitMQ 默认使用内存存储消息,但这种方式带来了两个主要问…

Openssl1.1.1s rpm包构建与升级

rpmbuild入门知识 openssh/ssl二进制升级 文章目录 前言一、资源准备1.下载openssh、openssl二进制包2.安装rpmbuild工具3.拷贝源码包到SOURCES目录下4.系统开启telnet,防止意外导致shh无法连接5.编译工具安装6.补充说明 二、制作 OpenSSL RPM 包1.编写 SPEC 文件2.…

【Unity3D】apk加密(global-metadata.dat加密)

涉及:apk、aab、global-metadata.dat、jks密钥文件、APKTool、zipalign 使用7z打开apk文件观察发现有如下3个针对加密的文件。 xxx.apk\assets\bin\Data\Managed\Metadata\global-metadata.dat xxx.apk\lib\armeabi-v7a\libil2cpp.so xxx.apk\lib\arm64-v8a\libil…

[免费]微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序(高校就业)招聘系统(Springboot后端Vue管理端),分享下哈。 项目视频演示 【免费】微信小程序(高校就业)招聘系统(Springboot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…

RNN心脏病预测-Pytorch版本

本文为为🔗365天深度学习训练营内部文章 原作者:K同学啊 一 导入数据 import numpy as np import pandas as pd import torch from torch import nn import torch.nn.functional as F import seaborn as sns from sklearn.preprocessing import Standard…

科普CMOS传感器的工作原理及特点

在当今数字化成像的时代,图像传感器无疑是幕后的关键 “功臣”,它宛如一位神奇的 “光影魔法师”,通过光电效应这一奇妙的物理现象,将光子巧妙地转换成电荷,为图像的诞生奠定基础。而在众多类型的图像传感器中&#xf…

Ubuntu 18.04 解决screen无法滚屏的问题

Ubuntu 18.04 解决screen无法滚屏的问题_ubuntu screen 无法上滑-CSDN博客文章浏览阅读2.7k次,点赞2次,收藏3次。在etc/screenrc中加入termcapinfo xterm* ti:te重新进入screen的sessionscreen -d -r XXX_ubuntu screen 无法上滑https://blog.csdn.net/w…

2025年01月09日Github流行趋势

1. 项目名称:khoj 项目地址url:https://github.com/khoj-ai/khoj项目语言:Python历史star数:22750今日star数:1272项目维护者:debanjum, sabaimran, MythicalCow, aam-at, eltociear项目简介:你…

Spring boot接入xxl-job

Spring boot接入xxl-job 导入maven包加入配置增加配置类创建执行器类&#xff08;写job的业务逻辑&#xff09;去控制台中配置job 导入maven包 <dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>…

Cglib动态代理中method.invoke与methodProxy.invokeSuper区别浅尝

前段时间看了黑马Spring教程中&#xff0c;有期视频讲解Cglib动态代理。 代码如下图&#xff1a; 可以看到调用目标对象的方法代码为&#xff1a; method.invoke(target,objects);在其他地方看到的此处代码是&#xff1a; methodProxy.invokeSuper(o,objects);注意&#xff…

【Linux 之一 】Linux常用命令汇总

Linux常用命令 ./catcd 命令chmodclearcphistoryhtoplnmkdirmvpwdrmtailunamewcwhoami 我从2021年4月份开始才开始真正意义上接触Linux&#xff0c;最初学习时是一脸蒙圈&#xff0c;啥也不会&#xff0c;啥也不懂&#xff0c;做了很多乱七八糟&#xff0c;没有条理的笔记。不知…