用 PyQt5 和 asyncio 打造接口并发测试 GUI 工具

news2025/4/25 10:50:37

接口并发测试是测试工程师日常工作中的重要一环,而一个直观的 GUI 工具能有效提升工作效率和体验。本篇文章将带你用 PyQt5 和 asyncio 从零实现一个美观且功能实用的接口并发测试工具。

我们将实现以下功能:

  1. 请求方法选择器
    添加了一个下拉框 QComboBox,用户可以选择 GETPOSTPUTDELETEPATCH

  2. 动态请求方法
    根据用户选择的请求方法,在 send_request 函数中动态调用对应的 aiohttp 方法(如 session.getsession.post)。

  3. 异常处理
    如果用户选择了不支持的请求方法,会返回 "Unsupported Method" 错误。


使用方法

  1. 在界面上输入请求的 URL
  2. 选择所需的 请求方法(如 GETPOST 等)。
  3. 输入 请求头请求参数(JSON 格式)。
  4. 设置 并发请求次数,点击“开始测试”。
  5. 查看结果表格中每个请求的序号、状态码和响应时间。

下面是完整的代码实现以及详细的注释,帮助你快速上手。
在这里插入图片描述


代码实现

1. 安装依赖

在开始之前,请确保安装了必要的依赖库:

pip install pyqt5 aiohttp

2. 主代码

以下是完整的代码实现:

import sys
import asyncio
import aiohttp
from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QTextEdit, QVBoxLayout, QHBoxLayout, QPushButton, QSpinBox, QTableWidget, QTableWidgetItem
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont

class AsyncHttpTester(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("接口并发测试工具")
        self.setGeometry(100, 100, 800, 600)
        self.setFont(QFont("Arial", 10))

        # === 接口配置区 ===
        url_label = QLabel("请求 URL:")
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("请输入接口 URL")

        headers_label = QLabel("请求头 (JSON 格式):")
        self.headers_input = QTextEdit()
        self.headers_input.setPlaceholderText('例如:{"Content-Type": "application/json"}')

        params_label = QLabel("请求参数 (JSON 格式):")
        self.params_input = QTextEdit()
        self.params_input.setPlaceholderText('例如:{"key": "value"}')

        times_label = QLabel("发送次数:")
        self.times_input = QSpinBox()
        self.times_input.setRange(1, 1000)
        self.times_input.setValue(1)

        # === 开始按钮 ===
        self.start_button = QPushButton("开始测试")
        self.start_button.clicked.connect(self.start_test)

        # === 结果展示区 ===
        results_label = QLabel("测试结果:")
        self.results_table = QTableWidget()
        self.results_table.setColumnCount(3)
        self.results_table.setHorizontalHeaderLabels(["请求序号", "状态码", "响应时间 (秒)"])
        self.results_table.setColumnWidth(0, 100)
        self.results_table.setColumnWidth(1, 100)
        self.results_table.setColumnWidth(2, 150)

        # === 布局 ===
        layout = QVBoxLayout()

        # 接口配置布局
        config_layout = QVBoxLayout()
        config_layout.addWidget(url_label)
        config_layout.addWidget(self.url_input)
        config_layout.addWidget(headers_label)
        config_layout.addWidget(self.headers_input)
        config_layout.addWidget(params_label)
        config_layout.addWidget(self.params_input)
        config_layout.addWidget(times_label)
        config_layout.addWidget(self.times_input)

        # 添加开始按钮
        config_layout.addWidget(self.start_button)

        # 结果展示布局
        results_layout = QVBoxLayout()
        results_layout.addWidget(results_label)
        results_layout.addWidget(self.results_table)

        # 整合布局
        layout.addLayout(config_layout)
        layout.addLayout(results_layout)
        self.setLayout(layout)

    async def send_request(self, session, url, headers, params, index):
        """发送单个 HTTP 请求"""
        try:
            async with session.post(url, json=params, headers=headers) as response:
                elapsed = response.elapsed.total_seconds() if response.elapsed else 0
                return index, response.status, elapsed
        except Exception as e:
            return index, f"Error: {str(e)}", 0

    async def start_async_requests(self, url, headers, params, times):
        """启动并发请求"""
        tasks = []
        async with aiohttp.ClientSession() as session:
            for i in range(times):
                tasks.append(self.send_request(session, url, headers, params, i + 1))
            return await asyncio.gather(*tasks)

    def start_test(self):
        """开始测试按钮事件"""
        url = self.url_input.text().strip()
        try:
            headers = eval(self.headers_input.toPlainText().strip()) if self.headers_input.toPlainText().strip() else {}
            params = eval(self.params_input.toPlainText().strip()) if self.params_input.toPlainText().strip() else {}
        except Exception as e:
            self.results_table.setRowCount(0)
            self.results_table.setRowCount(1)
            self.results_table.setItem(0, 0, QTableWidgetItem("Error"))
            self.results_table.setItem(0, 1, QTableWidgetItem(f"Invalid headers/params: {str(e)}"))
            return

        times = self.times_input.value()
        if not url:
            self.results_table.setRowCount(0)
            self.results_table.setRowCount(1)
            self.results_table.setItem(0, 0, QTableWidgetItem("Error"))
            self.results_table.setItem(0, 1, QTableWidgetItem("URL 不能为空"))
            return

        # 清空结果表
        self.results_table.setRowCount(0)

        # 启动异步任务
        loop = asyncio.get_event_loop()
        results = loop.run_until_complete(self.start_async_requests(url, headers, params, times))

        # 更新结果表
        self.results_table.setRowCount(len(results))
        for i, (index, status, elapsed) in enumerate(results):
            self.results_table.setItem(i, 0, QTableWidgetItem(str(index)))
            self.results_table.setItem(i, 1, QTableWidgetItem(str(status)))
            self.results_table.setItem(i, 2, QTableWidgetItem(f"{elapsed:.2f}"))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    tester = AsyncHttpTester()
    tester.show()
    sys.exit(app.exec_())

功能解析

1. 界面设计

  • 使用 PyQt5 构建界面,布局由 QVBoxLayoutQHBoxLayout 组合,模块化分为“配置区”和“结果区”。
  • 支持输入 URL、请求头、请求参数、以及指定发送次数。

2. 异步请求

  • 使用 aiohttp.ClientSession 实现非阻塞的 HTTP 请求。
  • 通过 asyncio.gather 并发发送多个请求,收集结果。

3. 响应展示

  • 结果以表格形式展示,包含请求序号、状态码、响应时间,方便对比和分析。

运行效果

  1. 启动工具后,用户可以在界面上输入接口参数,例如 URL、请求头、请求体等。
  2. 点击“开始测试”后,工具会并发发送指定次数的请求,并实时展示结果。

总结

通过 PyQt5 和 asyncio,我们成功实现了一个美观实用的接口并发测试工具。在这个项目中,测试工程师可以直观地配置接口参数并分析响应结果,同时也能深入理解 Python 的异步编程原理。

赶紧试试吧!

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

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

相关文章

Qt实战之将自定义插件(minGW)显示到Qt Creator列表的方法

Qt以其强大的跨平台特性和丰富的功能,成为众多开发者构建图形用户界面(GUI)应用程序的首选框架。而在Qt开发的过程中,自定义插件能够极大地拓展应用程序的功能边界,让开发者实现各种独特的、个性化的交互效果。想象一下…

【Vue】TypeScript与Vue3集成

个人主页:Guiat 归属专栏:Vue 文章目录 1. 前言2. 环境准备与基础搭建2.1. 安装 Node.js 与 npm/yarn/pnpm2.2. 创建 Vue3 TypeScript 项目2.2.1. 使用 Vue CLI2.2.2. 使用 Vite(推荐)2.2.3. 目录结构简述 3. Vue3 TS 基础语法整…

Linux之七大难命令(The Seven Difficult Commands of Linux)

Linux之七大难命令 、背景 作为Linux的初学者,肯定要先掌握高频使用的指令,这样才能让Linux的学习在短时间内事半功倍。但是,有些指令虽然功能强大,但因参数多而让初学者们很害怕,今天介绍Linux中高频使用&#xff0…

5.3.1 MvvmLight以及CommunityToolkit.Mvvm介绍

MvvmLight、CommunityToolkit.Mvvm是开源包,他们为实现 MVVM(Model-View-ViewModel)模式提供了一系列实用的特性和工具,能帮助开发者更高效地构建 WPF、UWP、MAUI 等应用程序。 本文介绍如下: 一、使用(旧)的MvvmLight库 其特点如下,要继承的基类是ViewModelBase;且使用…

Dbeaver 执行 SQL 语句和执行 SQL 脚本的区别

执行 SQL 语句 执行 SQL 语句对应图标: 适用于执行单个 SQL 的情形,默认是在光标处或选中的文本上执行 SQL 查询。 实际上同时选择多个 SQL 并通过该方式去执行也可能成功,只是有失败的风险。因此不建议使用它来同时执行多个 SQL 语句。 情况…

《Python3网络爬虫开发实战(第二版)》配套案例 spa6

Scrape | Moviehttps://spa6.scrape.center/ 请求影片列表api时,不仅有分页参数,还多了一个token,通过重发请求发现token有时间限制,所以得逆向token的生成代码。 通过xhr断点定位到接口请求位置 刷新页面或者点翻页按钮&#x…

Python基础语法:字面量,注释,关键字,标识符,变量和引用,程序执行的3大流程

目录 字面量(数据的类型) 字面量的含义 常见字面量类型(6种) 输出各类字面量(print语句) 注释(单行和多行注释) 注释的作用 单行注释和多行注释 单行注释(ctrl/&a…

SPL 量化 获取数据

下载数据 我们将股票数据分享在百度网盘上供下载,每工作日更新。 目前可供下载的数据有 A 股的日 K 线数据、股票代码列表和上市公司的基本面数据 下载链接: 百度网盘 下载数据的文件格式为 btx,是 SPL 的特有二进制格式。 btx 称为集文…

Rust 学习笔记:安装 Rust

Rust 学习笔记:安装 Rust Rust 学习笔记:安装 Rust在 Windows 上安装 Rust命令行创建 Rust 项目在 Mac/Linux 上安装 Rust一些命令升级卸载cargo -hrustc -h 安装 RustRoverrust-analyzer Rust 学习笔记:安装 Rust 在 Windows 上安装 Rust …

编译 C++ 报错“找不到 g++ 编译器”的终极解决方案(含 Windows/Linux/macOS)

前言 在使用终端编译 C 程序时,报错: 或类似提示,意味着你的系统尚未正确安装或配置 g 编译器。本篇将从零手把手教你在 Windows / Linux / macOS 下安装并配置 g,适用于新手或 C 入门阶段的你。 什么是 g? g 是 GN…

html单页业务介绍源码

源码介绍 html单页业务介绍源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行 效果预览 源码免费获取 html单页业务介绍源码

单体OJ项目

单体项目版本、微服务版还需我再钻研钻研。 项目介绍 在系统前台,管理员可以创建、管理题目;用户可以自由搜索题目、阅读题目、编写并提交代码。 在系统后端,能够根据管理员设定的题目测试用例在代码沙箱 中对代码进行编译、运行、判断输出是否正确。 其…

豆包桌面版 1.47.4 可做浏览器,免安装绿色版

自己动手升级更新办法: 下载新版本后安装,把 C:\Users\用户名\AppData\Local\Doubao\Application 文件夹的文件,拷贝替换 DoubaoPortable\App\Doubao 文件夹的文件,就升级成功了。 再把安装的豆包彻底卸载就可以。 桌面版比网页版…

【MySQL】索引失效问题详解

目录 1. 最左前缀原则 2. 条件左边有函数或运算 3. 隐式类型转换 4. LIKE 模糊查询以 % 开头 5、MySQL 优化器选择全表扫描 ⭐对 in 关键字特别说明⭐ (1)列表太大时,走全表扫描了 (2)隐式类型转换 &#xff…

优选算法第十讲:字符串

优选算法第十讲:字符串 1.最长公共前缀2.最长回文子串3.二进制求和4.字符串相乘 1.最长公共前缀 2.最长回文子串 3.二进制求和 4.字符串相乘

【扣子Coze 智能体案例四】五行八卦占卜智能体

目录 一、意图识别 二、时间格式转换 三、八字转换 四、八字提取 五、八字提取2 六、数据汇总 七、统计五行占比 八、雷达图生成 九、表格生成 十、AI占卜 十一、结束节点 一、意图识别 用户输入的信息包含各种时间格式的年月日时 用户输入的信息包含天干地支八字…

5.学习笔记-SpringMVC(P61-P70)

SpringMVC-SSM整合-接口测试 (1)业务层接口使用junit接口做测试 (2)表现层用postman做接口测试 (3)事务处理— 1)在SpringConfig.java,开启注解,是事务驱动 2)配置事务管理器(因为事务管理器是要配置数据源对象&…

【专题刷题】二分查找(一):深度解刨二分思想和二分模板

📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码;&#xff…

硬核解析!电动汽车能耗预测与续驶里程的关键技术研究

引言 随着电动汽车的普及,续航里程和能耗表现成为用户关注的核心痛点。然而,表显续航与实际续航的差异、低温环境下的电量衰减等问题始终困扰着消费者。本文基于《电动汽车能耗预测与续驶里程研究》的实验成果,深入剖析电动汽车能耗预测的核心模型、多环境测试方法及续航里…

【OceanBase相关】01-OceanBase数据库部署实践

文章目录 一、前言1、介绍说明2、部署方案二、部署说明1、环境准备2、软件安装2.1、安装OAT2.2、安装OCP3、软件部署三、集群管理1、MySQL租户管理四、Q&A1、OBServer 服务器重启后 observer 进程未能自动启动1.1、问题说明1.2、解决措施2、ERROR 1235 (0A000) at line 1: …