Python在接口测试中的应用

本文涉及的产品
NLP自然语言处理_基础版,每接口每天50万次
NLP 自学习平台,3个模型定制额度 1个月
NLP自然语言处理_高级版,每接口累计50万次
简介: 接口测试的方式有很多,可以使用的工具有jmeter,postman,soapUI等,也可以自己写代码进行接口测试(Python,java,go等等),工具的使用相对来说都比较简单,开箱即用。但如果接口中定义了一些需要加解密、数字签名等一些动态计算时,工具就很无助,唯有写代码进行实现测试。所以要根据接口协议,有针对性的进行选择工具,当工具不适合项目时需要进行工具开发。对于工具开发选择语言,语言本身没有优劣之分,选择自己擅长的和合适的。相对于java,go语言,Python不需要编译,而且支持的库很多,是其特点;其支持http协议接口的有urllib,urllib2以及requests库,支持we

1. 介绍

接口测试的方式有很多,可以使用的工具有jmeter,postman,soapUI等,也可以自己写代码进行接口测试(Python,java,go等等),工具的使用相对来说都比较简单,开箱即用。但如果接口中定义了一些需要加解密、数字签名等一些动态计算时,工具就很无助,唯有写代码进行实现测试。所以要根据接口协议,有针对性的进行选择工具,当工具不适合项目时需要进行工具开发。对于工具开发选择语言,语言本身没有优劣之分,选择自己擅长的和合适的。相对于java,go语言,Python不需要编译,而且支持的库很多,是其特点;其支持http协议接口的有urllib,urllib2以及requests库,支持websocket协议的库有websockets、websocket-client,支持grpc的库有grpcio、grpcio-tools,以及支持图形界面的PyQt5。本文中使用的Python版本为3.9.0,下面简单介绍下http、websocket、grpc接口示例,最后介绍使用PyQt5打造自己的测试工具。

2. http协议接口

对于http协议接口,requests库用起来最方便,因此采用requests库来做http协议的接口测试。安装requests:

pip install requests

2.1 GET请求示例

天气查询接口:http://wthrcdn.etouch.cn/weather_mini

import requests
r = requests.get('http://wthrcdn.etouch.cn/weather_mini')
print(r.text)

输出结果:'{"status":1002,"desc":"invilad-citykey"}'

2.2 带参数的GET请求示例

参数:city 城市名称

import requests
data ={}
data['city']='北京'
r = requests.get('http://wthrcdn.etouch.cn/weather_mini',params=data)
print(r.text)

输出结果:'{"data":{"yesterday":{"date":"31日星期二","high":"高温 27℃","fx":"南风","low":"低温 17℃","fl":"","type":"小雨"},"city":"北京","forecast":[{"date":"1日星期三","high":"高温 29℃","fengli":"","low":"低温 18℃","fengxiang":"南风","type":"晴"},{"date":"2日星期四","high":"高温 30℃","fengli":"","low":"低温 20℃","fengxiang":"南风","type":"晴"},{"date":"3日星期五","high":"高温 30℃","fengli":"","low":"低温 22℃","fengxiang":"南风","type":"阴"},{"date":"4日星期六","high":"高温 26℃","fengli":"","low":"低温 21℃","fengxiang":"南风","type":"中雨"},{"date":"5日星期天","high":"高温 26℃","fengli":"","low":"低温 20℃","fengxiang":" 东风","type":"小雨"}],"ganmao":"感冒易发期,外出请适当调整衣物,注意补充水分。","wendu":"23"},"status":1000,"desc":"OK"}'

假如服务对请求中city的一致性进行校验,header中需要传入Authorization,为city值的md5

import hashlib
data ={}
data['city']='合肥'
auth=hashlib.md5(data['city'].encode(encoding='utf-8')).hexdigest()
headers = {'Authorization': auth}
r = requests.get('http://wthrcdn.etouch.cn/weather_mini',params=data,headers=headers)
print(r.text)

输出结果:'{"data":{"yesterday":{"date":"31日星期二","high":"高温 35℃","fx":"南风","low":"低温 25℃","fl":"","type":"晴"},"city":"合肥","forecast":[{"date":"1日星期三","high":"高温 30℃","fengli":"","low":"低温 24℃","fengxiang":"北风","type":"小雨"},{"date":"2日星期四","high":"高温 26℃","fengli":"","low":"低温 23℃","fengxiang":"西北风","type":"阴"},{"date":"3日星期五","high":"高温 29℃","fengli":"","low":"低温 23℃","fengxiang":"东风","type":"多云"},{"date":"4日星期六","high":"高温 29℃","fengli":"","low":"低温 24℃","fengxiang":"东风","type":"小雨"},{"date":"5日星期天","high":"高温 31℃","fengli":"","low":"低温 24℃","fengxiang":"东北风","type":"小雨"}],"ganmao":"感冒低发期,天气舒适,请注意多吃蔬菜水果,多喝水哦。","wendu":"26"},"status":1000,"desc":"OK"}'

2.3 POST请求示例

本示例使用requests官网示例,POST请求不再多介绍,可参考官网。Github API v3 接受编码为JSON的POST数据

import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload))

3. Websocket协议接口

安装websockets库

pip install websockets

下面是一个NLP接口的例子,客户端连接服务端,发送文本,接收返回结果,其中文本需要进行base64加密。

import uuid
import websockets
async def send_msg(websocket):
    text = '我要查余额'
    bs = str(base64.b64encode(text.encode('utf-8')), 'utf-8')
    sid = uuid.uuid4()
    timestamp = str(int(time.time()) * 1000)
    msg = '{"app":"test","sn":"123","timeStamp":"' + timestamp + '","version":"1.0.0","data":"' + bs + '",' \
          '"sid":"' + str(sid) + '"} '
    print(msg)
    await websocket.send(msg)
    rev_text = await websocket.recv()
    print(rev_text)
async def client():
    async with websockets.connect('ws://xxx.xxx.com/nlp') as websocket:
        await send_msg(websocket)
if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(client())

执行结果示例:{"appid":"test","sn":"123","timeStamp":"1630586234000","version":"1.0.0","data":"5oiR6KaB5p+l6K+i5L2Z6aKd",sid":"4c6f5a64-2374-4616-9385-376c0d25bc1e"}{"code":"0000","msg":"succ","nlp":"{"sceneKey":"","sid":"d28c7631-54d9-493e-8db8-f67a5ecc2a25","uid":"d28c7631-54d9-493e-8db8-f67a5ecc2a25","text":"我要查询余额",,"semantic":[{"intent":"querybalance","intentName":"查询余额","intentCnxt":"","template":"{Query}余额","score":0.865519,"slots":[]}],"dialog":{"status":0,"uid":"","reaction":{"text":""},"slots":null},"answer":{"answerType":"","text":"","emotion":"","topic":"","topicID":"","type":"","question":{"question":"","question_ws":""}}}","extendData":"","sid":"d28c7631-54d9-493e-8db8-f67a5ecc2a25","last":true}

4. grpc协议接口

grpc协议需要Python 3.5版本以上,安装所需的库:

pip install grpcio
pip install grpcio-tools

下面以虚拟主播服务接口为例,服务使用了grpc双向流进行交互,与服务端建立连接后,会返回一个rtmp地址,推送虚拟主播视频流,向服务端发送文本,会驱动虚拟主播播报文本。

4.1 编写avatar.proto文件

syntax = "proto3";
package protocol;
message AvatarRequest {
  string  app = 1;
  string  timestamp = 2;
  string  version = 3;
  string  anchorId = 4;
  string  vcn = 5;
  bytes   data = 6;
  int32   width = 7;
  int32   height = 8;
  string  type=9;
}
message AvatarResponse {
  string  code = 1;
  string  msg = 2;
  string  type = 3;
  bytes   data = 4;
  string  status = 5;
  string  sessionId = 6;
}
service AvatarInteraction {
  rpc Interact (stream AvatarRequest) returns (stream AvatarResponse) {
  }
}

4.2 使用工具生成grpc代码

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./avatar.proto最终生成avatar_pb2.py和avatar_pb2_grpc.py两个文件

4.3 grpc请求示例

将上述两个文件,引入到项目代码中

import sys
import threading
import time
import grpc
import avatar_pb2 as pb
import avatar_pb2_grpc as avatar
class avatarClient(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.status = False
        self.serverUrl = ""
        self.anchorId = '1001'
        self.vcn = 'xiaoyuan'
        self.app = 'testapp'
        self.type = '0'
        self.sendTxt = False
        self.text = ""
        self.connectType = '1001'
        self.pingType = '-1000'
        self.width = 1080
        self.height = 1920
        self.sid = ""
        self.print_res = printRes()
        self.lastPingTime = int(time.time() * 1000)
    # 连接服务
    def connect_sever(self):
        return pb.AvatarRequest(app=self.app, timestamp=str(int(time.time() * 1000)), version='1.0.0',
                                anchorId=self.anchorId, vcn=self.vcn, type=self.connectType, width=self.width,
                                height=self.height)
    # 发送文本
    def send_text(self):
        return pb.AvatarRequest(app=self.app, timestamp=str(int(time.time() * 1000)), version='1.0.0',
                                anchorId=self.anchorId, vcn=self.vcn, type='3', data=str(self.text).encode('utf-8'))
    # 发送ping
    def send_ping(self):
        return pb.AvatarRequest(app=self.app, timestamp=str(int(time.time() * 1000)), version='1.0.0',
                                anchorId=self.anchorId, vcn=self.vcn, type=self.pingType)
    def send_message(self):
        yield self.connect_sever()
    #间隔10秒,发送ping,进行连接保活
        while True:
            if self.sendTxt:
                yield self.send_text()
                self.sendTxt = False
            if (int(time.time() * 1000) - int(self.lastPingTime)) < 10000:
                continue
            else:
                yield self.send_ping()
                self.lastPingTime = int(time.time() * 1000)
    def run(self):
        self.status = True
        if self.serverUrl == "":
            return
        with grpc.insecure_channel(self.serverUrl) as channel:
            stub = avatar.AvatarInteractionStub(channel)
            self.channel = channel
            responses = stub.Interact(self.send_message())
            self.print_res.setClient(responses, self)
            self.print_res.start()
            time.sleep(1)
            while True:
                if self.print_res.runStatus == False:
                    break
                client.text = input("input your text:\n")
                client.sendTxt = True
                time.sleep(1)
    def stop(self):
        try:
            self.status = False
            self.print_res.runStatus = False
            time.sleep(1)
        except KeyboardInterrupt:
            pass
class printRes(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.runStatus = True
    def setClient(self, responses, client):
        self.responses = responses
        self.client = client
    def run(self):
        try:
            for response in self.responses:
                print(response)
                if not self.runStatus:
                    sys.exit(0)
                if response.code != "000000":
                    self.runStatus = False
                    sys.exit(0)
        except Exception:
            print("err")
if __name__ == '__main__':
    client = avatarClient()
    client.serverUrl = "xxx.xxx.xxx.xxx:xxxx"
    client.start()

5. 打造自己的测试工具

在编辑器中执行测试,有时候交互性不太友好,因此我们可以打造一个带交互界面的测试工具。QT是跨平台C++库的集合,它实现高级API来访问现代桌面和移动系统的许多方面。这些服务包括定位和定位服务、多媒体、NFC和蓝牙连接、基于铬的web浏览器以及传统的UI开发。PyQt5是一套针对QtV5的全面Python绑定。它被实现为超过35个扩展模块,并使Python可以作为一个替代的应用程序开发语言C++在所有支持的平台上包括IOS和Android。

5.1 安装PyQt5

pip install PyQt5

如果要使用图像界面进行设计,可以安装Qt Designer图形界面开发工具,相关配置可以自行搜索。

pip install PyQt5-tools

5.2 打造websocket测试工具

下面以websocket接口为例,实现一个nlp的测试工具

# -*- coding: utf-8 -*-
import sys
import asyncio
import base64
import time
import uuid
import websockets
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import *
class Ui_mainWindow(object):
    def __init__(self, mainWindow):
        self.mainWindow = mainWindow
        self.setupUi()
    def setupUi(self):
        self.mainWindow.setObjectName("mainWindow")
        self.mainWindow.setWindowModality(QtCore.Qt.WindowModal)
        self.mainWindow.resize(600, 300)
        self.mainWindow.setWindowTitle("NLP测试工具")
        self.centralwidget = QtWidgets.QWidget(self.mainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.widget1 = QtWidgets.QWidget(self.centralwidget)
        self.widget1.setGeometry(QtCore.QRect(10, 30, 400, 25))
        self.widget1.setObjectName("widget1")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget1)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.serverUrlLabel = QtWidgets.QLabel(self.widget1)
        self.serverUrlLabel.setObjectName("label")
        self.serverUrlLabel.setText("服务地址:")
        self.horizontalLayout.addWidget(self.serverUrlLabel)
        self.serverUrlLineEdit = QtWidgets.QLineEdit(self.widget1)
        self.serverUrlLineEdit.setEnabled(True)
        self.serverUrlLineEdit.setText("ws://xxx..xxx.xxx/nlp")
        self.serverUrlLineEdit.setMinimumWidth(320)
        self.serverUrlLineEdit.setMaximumWidth(320)
        self.serverUrlLineEdit.setObjectName("serverUrlLineEdit")
        self.horizontalLayout.addWidget(self.serverUrlLineEdit, stretch=500, alignment=QtCore.Qt.AlignLeft)
        self.sendTextWidget = QtWidgets.QWidget(self.centralwidget)
        self.sendTextWidget.setGeometry(QtCore.QRect(0, 70, 500, 70))
        self.sendTextWidget.setObjectName("sendTextWidget")
        self.sendTextLayout = QtWidgets.QHBoxLayout(self.sendTextWidget)
        self.sendTextLayout.setContentsMargins(0, 0, 0, 0)
        self.sendTextLayout.setObjectName("sendTextLayout")
        self.sendTextLabel = QtWidgets.QLabel(self.sendTextWidget)
        self.sendTextLabel.setContentsMargins(20, 0, 0, 0)
        self.sendTextLabel.setText("文本:")
        self.sendTextLayout.addWidget(self.sendTextLabel)
        self.sendTextTextEdit = QtWidgets.QTextEdit(self.sendTextWidget)
        self.sendTextTextEdit.setObjectName("sendTextTextEdit")
        self.sendTextLayout.addWidget(self.sendTextTextEdit)
        self.sendTextButton = QtWidgets.QPushButton(self.sendTextWidget)
        self.sendTextButton.setObjectName("sendText")
        self.sendTextButton.setText("发送")
        self.sendTextButton.clicked.connect(self.send_text)
        self.sendTextLayout.addWidget(self.sendTextButton)
        self.widget3 = QtWidgets.QWidget(self.centralwidget)
        self.widget3.setGeometry(QtCore.QRect(0, 160, 420, 90))
        self.widget3.setObjectName("widget3")
        self.logLayout = QtWidgets.QHBoxLayout(self.widget3)
        self.logLayout.setContentsMargins(0, 0, 0, 0)
        self.logLayout.setObjectName("logLayout")
        self.logLabel = QtWidgets.QLabel(self.widget3)
        self.logLabel.setObjectName("logLabel")
        self.logLabel.setContentsMargins(20, 0, 0, 0)
        self.logLabel.setLineWidth(30)
        self.logLabel.setText("返回:")
        self.logLayout.addWidget(self.logLabel)
        self.logTextEdit = QtWidgets.QTextEdit(self.widget3)
        self.logTextEdit.setContentsMargins(0, 0, 0, 0)
        self.logTextEdit.setObjectName("logTextEdit")
        self.logLayout.addWidget(self.logTextEdit)
        self.mainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(self.mainWindow)
        self.statusbar.setObjectName("statusbar")
        self.mainWindow.setStatusBar(self.statusbar)
        QtCore.QMetaObject.connectSlotsByName(self.mainWindow)
    def send_text(self):
        self.websocketClient = WebsocketClient()
        self.websocketClient.url = self.serverUrlLineEdit.text()
        self.websocketClient.text = self.sendTextTextEdit.toPlainText()
        result = self.websocketClient.run()
        self.logTextEdit.setText(result)
class WebsocketClient:
    def __init__(self):
        self.url = ""
    async def send_msg(self, websocket):
        if self.text == "":
            return "empty text"
        bs = str(base64.b64encode(self.text.encode('utf-8')), 'utf-8')
        sid = uuid.uuid4()
        timestamp = str(int(time.time()) * 1000)
    msg = '{"app":"test","sn":"123","timeStamp":"' + timestamp + '","version":"1.0.0","data":"' + bs + '",' \
      '"sid":"' + str(sid) + '"} '
        await websocket.send(msg)
        rev_text = await websocket.recv()
        self.result = rev_text
        self.text = ""
        return rev_text
    async def connect(self):
        try:
            async with websockets.connect(self.url) as websocket:
                res = await self.send_msg(websocket)
                return res
        except Exception as e:
            return str(e)
    def run(self):
        return asyncio.get_event_loop().run_until_complete(self.connect())
if __name__ == "__main__":
    app = QApplication(sys.argv)
  window = QMainWindow()
  box = Ui_mainWindow(window)
  window.show()
    sys.exit(app.exec_())

执行结果:

5.3 虚拟主播工具介绍

上一节中,介绍了虚拟主播服务grpc接口示例,那么可以使用PyQt5打造虚拟主播的测试工具,此处不再提供示例代码,运行如下图:

相关文章
|
1天前
|
数据可视化 Python
Python绘制基频曲线——实例解析与应用探讨
Python绘制基频曲线——实例解析与应用探讨
19 9
|
1天前
|
敏捷开发 Java 测试技术
自动化测试框架的选择与应用
【9月更文挑战第26天】在软件开发的海洋里,自动化测试是那一盏指路明灯。它不仅加快了开发周期,还提升了软件质量。本文将带你探索自动化测试框架的世界,了解它们的核心特性、适用场景及如何根据项目需求做出明智选择。让我们一起启航,找到那把打开高效、稳定软件生产大门的钥匙。
|
2天前
|
JavaScript 前端开发 UED
WebSocket在Python Web开发中的革新应用:解锁实时通信的新可能
在快速发展的Web应用领域中,实时通信已成为许多现代应用不可或缺的功能。传统的HTTP请求/响应模式在处理实时数据时显得力不从心,而WebSocket技术的出现,为Python Web开发带来了革命性的变化,它允许服务器与客户端之间建立持久的连接,从而实现了数据的即时传输与交换。本文将通过问题解答的形式,深入探讨WebSocket在Python Web开发中的革新应用及其实现方法。
10 3
|
1天前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
6 1
|
2天前
|
机器学习/深度学习 人工智能 监控
软件测试中的人工智能应用与挑战
随着科技的迅猛发展,人工智能(AI)在软件测试中的应用越来越广泛。本文将探讨AI在软件测试中的具体应用场景、带来的优势以及所面临的挑战,旨在为软件开发和测试人员提供有价值的参考。
|
2天前
|
机器学习/深度学习 物联网 算法框架/工具
探索Python的魅力与应用
在这篇文章中,我们将深入探讨Python编程语言的各个方面。从它的起源和设计理念开始,到具体的应用场景和技术实现,我们将一步步揭示Python成为现代编程领域中不可或缺的工具的原因。无论是对于初学者还是有经验的开发者来说,Python的魅力都不容小觑。
10 1
|
3天前
|
机器学习/深度学习 数据可视化 TensorFlow
探索Python在数据科学中的应用
这篇文章深入探讨了Python编程语言在数据科学领域的强大应用。从数据处理、分析到可视化,再到机器学习和深度学习,Python因其丰富的库和框架而成为数据科学家的首选工具。文章不仅介绍了Python的基本语法和数据结构,还详细讨论了如何使用Pandas进行数据清洗和预处理,以及NumPy和SciPy在数值计算中的重要性。此外,文章还涵盖了使用Matplotlib和Seaborn进行数据可视化的技巧,以及Scikit-learn和TensorFlow在构建预测模型中的应用。通过综合运用这些工具,数据科学家能够更有效地分析大量复杂的数据集,从而洞察趋势、模式和关联性,支持决策制定和策略优化。
10 2
|
3天前
|
测试技术 持续交付 UED
软件测试的艺术与科学:平衡创新与质量的探索在软件开发的波澜壮阔中,软件测试如同灯塔,指引着产品质量的方向。本文旨在深入探讨软件测试的核心价值,通过分析其在现代软件工程中的应用,揭示其背后的艺术性与科学性,并探讨如何在追求技术创新的同时确保产品的高质量标准。
软件测试不仅仅是技术活动,它融合了创造力和方法论,是软件开发过程中不可或缺的一环。本文首先概述了软件测试的重要性及其在项目生命周期中的角色,随后详细讨论了测试用例设计的创新方法、自动化测试的策略与挑战,以及如何通过持续集成/持续部署(CI/CD)流程优化产品质量。最后,文章强调了团队间沟通在确保测试有效性中的关键作用,并通过案例分析展示了这些原则在实践中的应用。
14 1
|
16天前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
77 7
Jmeter实现WebSocket协议的接口测试方法
|
16天前
|
JSON 移动开发 监控
快速上手|HTTP 接口功能自动化测试
HTTP接口功能测试对于确保Web应用和H5应用的数据正确性至关重要。这类测试主要针对后台HTTP接口,通过构造不同参数输入值并获取JSON格式的输出结果来进行验证。HTTP协议基于TCP连接,包括请求与响应模式。请求由请求行、消息报头和请求正文组成,响应则包含状态行、消息报头及响应正文。常用的请求方法有GET、POST等,而响应状态码如2xx代表成功。测试过程使用Python语言和pycurl模块调用接口,并通过断言机制比对实际与预期结果,确保功能正确性。
75 3
快速上手|HTTP 接口功能自动化测试