使用python和asyncio打造接口并發(fā)測(cè)試GUI工具
前言
接口并發(fā)測(cè)試是測(cè)試工程師日常工作中的重要一環(huán),而一個(gè)直觀的 GUI 工具能有效提升工作效率和體驗(yàn)。本篇文章將帶你用 PyQt5 和 asyncio 從零實(shí)現(xiàn)一個(gè)美觀且功能實(shí)用的接口并發(fā)測(cè)試工具。
我們將實(shí)現(xiàn)以下功能:
請(qǐng)求方法選擇器
添加了一個(gè)下拉框 QComboBox,用戶可以選擇 GET、POST、PUT、DELETE 或 PATCH。
動(dòng)態(tài)請(qǐng)求方法
根據(jù)用戶選擇的請(qǐng)求方法,在 send_request 函數(shù)中動(dòng)態(tài)調(diào)用對(duì)應(yīng)的 aiohttp 方法(如 session.get 或 session.post)。
異常處理
如果用戶選擇了不支持的請(qǐng)求方法,會(huì)返回 "Unsupported Method" 錯(cuò)誤。
使用方法
在界面上輸入請(qǐng)求的 URL。
選擇所需的 請(qǐng)求方法(如 GET、POST 等)。
輸入 請(qǐng)求頭 和 請(qǐng)求參數(shù)(JSON 格式)。
設(shè)置 并發(fā)請(qǐng)求次數(shù),點(diǎn)擊“開始測(cè)試”。
查看結(jié)果表格中每個(gè)請(qǐng)求的序號(hào)、狀態(tài)碼和響應(yīng)時(shí)間。
下面是完整的代碼實(shí)現(xiàn)以及詳細(xì)的注釋,幫助你快速上手。

代碼實(shí)現(xiàn)
1. 安裝依賴
在開始之前,請(qǐng)確保安裝了必要的依賴庫(kù):
pip install pyqt5 aiohttp
2. 主代碼
以下是完整的代碼實(shí)現(xiàn):
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("接口并發(fā)測(cè)試工具")
self.setGeometry(100, 100, 800, 600)
self.setFont(QFont("Arial", 10))
# === 接口配置區(qū) ===
url_label = QLabel("請(qǐng)求 URL:")
self.url_input = QLineEdit()
self.url_input.setPlaceholderText("請(qǐng)輸入接口 URL")
headers_label = QLabel("請(qǐng)求頭 (JSON 格式):")
self.headers_input = QTextEdit()
self.headers_input.setPlaceholderText('例如:{"Content-Type": "application/json"}')
params_label = QLabel("請(qǐng)求參數(shù) (JSON 格式):")
self.params_input = QTextEdit()
self.params_input.setPlaceholderText('例如:{"key": "value"}')
times_label = QLabel("發(fā)送次數(shù):")
self.times_input = QSpinBox()
self.times_input.setRange(1, 1000)
self.times_input.setValue(1)
# === 開始按鈕 ===
self.start_button = QPushButton("開始測(cè)試")
self.start_button.clicked.connect(self.start_test)
# === 結(jié)果展示區(qū) ===
results_label = QLabel("測(cè)試結(jié)果:")
self.results_table = QTableWidget()
self.results_table.setColumnCount(3)
self.results_table.setHorizontalHeaderLabels(["請(qǐng)求序號(hào)", "狀態(tài)碼", "響應(yīng)時(shí)間 (秒)"])
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)
# 結(jié)果展示布局
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):
"""發(fā)送單個(gè) HTTP 請(qǐng)求"""
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):
"""啟動(dòng)并發(fā)請(qǐng)求"""
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):
"""開始測(cè)試按鈕事件"""
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
# 清空結(jié)果表
self.results_table.setRowCount(0)
# 啟動(dòng)異步任務(wù)
loop = asyncio.get_event_loop()
results = loop.run_until_complete(self.start_async_requests(url, headers, params, times))
# 更新結(jié)果表
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. 界面設(shè)計(jì)
使用 PyQt5 構(gòu)建界面,布局由 QVBoxLayout 和 QHBoxLayout 組合,模塊化分為“配置區(qū)”和“結(jié)果區(qū)”。
支持輸入 URL、請(qǐng)求頭、請(qǐng)求參數(shù)、以及指定發(fā)送次數(shù)。
2. 異步請(qǐng)求
使用 aiohttp.ClientSession 實(shí)現(xiàn)非阻塞的 HTTP 請(qǐng)求。
通過 asyncio.gather 并發(fā)發(fā)送多個(gè)請(qǐng)求,收集結(jié)果。
3. 響應(yīng)展示
結(jié)果以表格形式展示,包含請(qǐng)求序號(hào)、狀態(tài)碼、響應(yīng)時(shí)間,方便對(duì)比和分析。
運(yùn)行效果
啟動(dòng)工具后,用戶可以在界面上輸入接口參數(shù),例如 URL、請(qǐng)求頭、請(qǐng)求體等。
點(diǎn)擊“開始測(cè)試”后,工具會(huì)并發(fā)發(fā)送指定次數(shù)的請(qǐng)求,并實(shí)時(shí)展示結(jié)果。
總結(jié)
通過 PyQt5 和 asyncio,我們成功實(shí)現(xiàn)了一個(gè)美觀實(shí)用的接口并發(fā)測(cè)試工具。在這個(gè)項(xiàng)目中,測(cè)試工程師可以直觀地配置接口參數(shù)并分析響應(yīng)結(jié)果,同時(shí)也能深入理解 Python 的異步編程原理。
到此這篇關(guān)于使用python和asyncio打造接口并發(fā)測(cè)試GUI工具的文章就介紹到這了,更多相關(guān)python asyncio接口并發(fā)測(cè)試內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python利用Turtle繪制Technoblade的示例代碼
國(guó)外一位在YouTube擁有上千萬粉絲的我的世界游戲主播Technoblade因癌癥與世長(zhǎng)辭,為了紀(jì)念他,特地寫了這篇文章,教大家用Turtle繪制出Technoblade,快跟隨小編一起學(xué)習(xí)一下吧2023-01-01
Python開發(fā)中使用read()讀取大文件導(dǎo)致內(nèi)存溢出問題解決辦法
在處理大型Excel文件時(shí),開發(fā)者常遇到程序崩潰或響應(yīng)緩慢的問題,其核心原因在于內(nèi)存溢出,這篇文章主要介紹了Python開發(fā)中使用read()讀取大文件導(dǎo)致內(nèi)存溢出問題的解決辦法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-06-06
python 從csv讀數(shù)據(jù)到mysql的實(shí)例
今天小編就為大家分享一篇python 從csv讀數(shù)據(jù)到mysql的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-06-06
Python input函數(shù)實(shí)現(xiàn)獲取鍵盤輸入的字符串流程講解
這篇文章主要介紹了Python input函數(shù)實(shí)現(xiàn)獲取鍵盤輸入的字符串流程,input()是Python的內(nèi)置函數(shù),用于從控制臺(tái)讀取用戶輸入的內(nèi)容。input()函數(shù)總是以字符串的形式來處理用戶輸入的內(nèi)容,所以用戶輸入的內(nèi)容可以包含任何字符2023-01-01
Python?+?Tkinter連接本地MySQL數(shù)據(jù)庫(kù)簡(jiǎn)單實(shí)現(xiàn)注冊(cè)登錄
這篇文章主要介紹了Python?+?Tkinter連接本地MySQL數(shù)據(jù)庫(kù)簡(jiǎn)單實(shí)現(xiàn)注冊(cè)登錄。下面文章著情介紹,需要的小伙伴可以參考一下2022-01-01
python3格式化字符串 f-string的高級(jí)用法(推薦)
從Python 3.6開始,f-string是格式化字符串的一種很好的新方法。與其他格式化方式相比,它們不僅更易讀,更簡(jiǎn)潔,不易出錯(cuò),而且速度更快!本文重點(diǎn)給大家介紹python3格式化字符串 f-string的高級(jí)用法,一起看看吧2020-03-03

