【Python】从同步到异步多核:测试桩性能优化,加速应用的开发和验证

目录

测试工作中常用到的测试桩mock能力

应用场景

简单测试桩

http.server扩展:一行命令实现一个静态文件服务器

性能优化:使用异步响应

异步响应

能优化:利用多核

gunicorn

安装 gunicorn

使用 gunicorn 启动服务

性能优化:使用缓存(functools.lru_cache)。

单元测试中的mock

Python unittest.mock

总结

资料获取方法


测试工作中常用到的测试桩mock能力

在我们的测试工作过程中,可能会遇到前端服务开发完成,依赖服务还在开发中;或者我们需要压测某个服务,而这个服务的依赖组件(如测试环境MQ) 无法支撑并发访问的场景。这个时候我们可能就需要一个服务,来替代测试环境的这些依赖组件或服务,而这就是本文的主角--测试桩

测试桩可以理解为一个代理,它可以用于模拟应用程序中的外部依赖项,如数据库、网络服务或其他API,它可以帮助我们在开发和测试过程中隔离应用程序的不同部分,从而使测试更加可靠和可重复。

应用场景

测试桩使用的一般有以下几种场景:

场景使用测试桩的原因与目的
单元测试隔离被测代码与其他组件或外部依赖的交互,便于在不考虑其他部分的情况下对被测代码进行测试。
集成测试当某些组件未实现或不可用时,使用测试桩模拟这些组件,以便继续进行集成测试。
性能测试快速生成高负载和大量并发请求,评估系统在高负载条件下的性能表现。
故障注入和恢复测试模拟故障(如网络故障、服务宕机等),验证系统在遇到故障时的行为和恢复能力。
API测试使用测试桩模拟API的响应,以便在API实现完成之前就可以进行客户端开发和测试。
第三方服务测试在开发和测试阶段避免与真实的第三方服务进行交互,降低额外成本和不稳定的测试结果。测试桩用于模拟这些第三方服务,使得在不影响真实服务的情况下进行测试。

本文将选取常用的几个场景循序渐进地介绍测试桩的开发和优化。

简单测试桩

如果在测试环境中不方便安装其他的库,我们可以使用Python标准库中的一个模块http.server模块创建一个简单的HTTP请求测试桩。

# simple_stub.py
# 测试桩接收GET请求并返回JSON数据。
import json
from http.server import BaseHTTPRequestHandler, HTTPServerclass SimpleHTTPRequestHandler(BaseHTTPRequestHandler):def do_GET(self):content = json.dumps({"message": "Hello, this is a test stub!"}).encode("utf-8")self.send_response(200)self.send_header("Content-Type", "application/json")self.send_header("Content-Length", f"{len(content)}")self.end_headers()self.wfile.write(content)if __name__ == "__main__":server_address = ("", 8000)httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)print("Test stub is running on port 8000")httpd.serve_forever()

运行上面的代码,将看到测试桩正在监听8000端口。您可以使用浏览器或curl命令访问 http://localhost:8000,将会收到 {'message': 'Hello, this is a test stub!'}的响应。

http.server扩展:一行命令实现一个静态文件服务器

http.server模块可以作为一个简单的静态文件服务器,用于在本地开发和测试静态网站。要启动静态文件服务器,请在命令行中运行以下命令:

python3 -m http.server [port]

其中[port]是可选的端口号,不传递时默认为8000。服务器将在当前目录中提供静态文件。

如在日志文件夹中执行python -m http.server,就能在web浏览器中访问这个文件夹中的文件和子文件夹的内容:

image

注意: http.server主要用于开发和测试,性能和安全方面不具备在生产环境部署的条件

性能优化:使用异步响应

我们在前面的实现了一个简单的测试桩,但在实际应用中,我们可能需要更高的性能和更复杂的功能。

异步响应

在只有同样的资源的情况下,像这样的有网络I/O的服务,使用异步的方式无疑能更有效地利用系统资源。

说到异步的http框架,目前最火热的当然是FastAPI,使用FastAPI实现上面的功能只需两步。

首先,安装FastAPI和Uvicorn:

pip install fastapi uvicorn

接下来,创建一个名为fastapi_stub.py的文件,其中包含以下内容:

from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def get_request():return {"message": "Hello, this is an optimized test stub!"}if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

执行代码,这个测试桩也是监听在8000端口。我们可以像之前那样使用浏览器或其他HTTP客户端向测试桩发起请求。

点击查看异步编程优势 介绍

能优化:利用多核

虽然我们前面使用到了异步的方式来提升测试桩的性能,但是代码还是只是跑在一个CPU核心上,如果我们要进行性能压测,可能无法满足我们的性能需求。这个时候我们可以使用 gunicorn库 来利用上服务器的多核优势。

gunicorn

Gunicorn的主要特点和优势:

特点与优势说明
简单易用Gunicorn易于安装和配置,可以与许多Python Web框架(如Flask、Django、FastAPI等)无缝集成。
多进程Gunicorn使用预先分叉的工作模式,创建多个子进程处理并发请求。这有助于提高应用程序的性能和响应能力。
兼容性Gunicorn遵循WSGI规范,这意味着它可以与遵循WSGI规范的任何Python Web应用程序一起使用。
可配置性Gunicorn提供了许多配置选项,如工作进程数量、工作进程类型(同步、异步)、超时设置等。这使得Gunicorn可以根据具体需求进行灵活配置。
部署友好Gunicorn在生产环境中非常受欢迎,因为它简化了部署流程。Gunicorn可以与其他工具(如Nginx、Supervisor等)一起使用,以便更好地管理和扩展Web应用程序。
安装 gunicorn
pip install gunicorn
使用 gunicorn 启动服务

启动服务:

gunicorn -w 4  fastapi_stub:app 

可以看到,上面的命令启动了4个worker 进程,大家也可以使用ps -ef命令查询一下进程状态。

image

gunicorn的一些常用参数:

参数说明
-w, --workers设置工作进程的数量。根据系统的CPU核心数和应用程序的负载特征来调整。默认值为1。
-k, --worker-class设置工作进程的类型。可以是sync(默认)、geventeventlet等。如果使用异步工作进程,需要安装相应的库。例如,对于FastAPI应用程序,可以使用-k uvicorn.workers.UvicornWorker
-b, --bind设置服务器绑定的地址和端口。格式为address:port。例如:-b 0.0.0.0:8000。默认值为127.0.0.1:8000
--timeout设置工作进程的超时时间(以秒为单位)。如果工作进程在指定的时间内没有完成任务,它将被重启。默认值为30秒。
--log-level设置日志级别。可以是debuginfowarningerrorcritical。默认值为info
--access-logfile设置访问日志文件的路径。默认情况下,访问日志将输出到标准错误流。要禁用访问日志,请使用-。例如:--access-logfile -
--error-logfile设置错误日志文件的路径。默认情况下,错误日志将输出到标准错误流。要禁用错误日志,请使用-。例如:--error-logfile -
--reload在开发环境中使用此选项,当应用程序代码发生更改时,Gunicorn将自动重新加载。不建议在生产环境中使用。
--daemon使用此选项以守护进程模式运行Gunicorn。在这种模式下,Gunicorn将在后台运行,并在启动时自动分离。

Gunicorn提供了许多其他配置选项,可以根据具体需求进行调整。要查看完整的选项列表,可以查看Gunicorn的官方文档:https://docs.gunicorn.org/en/stable/settings.html。

性能优化:使用缓存(functools.lru_cache)。

当处理重复的计算或数据检索任务时。使用内存缓存(如Python的functools.lru_cache)或外部缓存(如Redis)来缓存经常使用的数据也能极大的提升测试桩的效率。

假设我们的测试桩需要使用到计算计算斐波那契数列这样耗时的功能,那么缓存结果,在下次遇到同样的请求时直接返回而不是先计算再返回,将极大的提高资源的使用率、减少响应的等待时间

如果仅仅是直接返回数据的,没有进行复杂的计算的测试桩,使用lru_cache并没有实际意义。

以下是一个更合适的使用lru_cache的示例,其中我们将对斐波那契数列进行计算并缓存结果:

from fastapi import FastAPI
from functools import lru_cacheapp = FastAPI()@lru_cache(maxsize=100)
def fibonacci(n: int):if n <= 1:return nelse:return fibonacci(n - 1) + fibonacci(n - 2)@app.get("/fibonacci/{n}")
async def get_fibonacci(n: int):result = fibonacci(n)return {"result": result}if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

在这个示例中,我们使用FastAPI创建了一个简单的HTTP请求测试桩。我们定义了一个名为fibonacci的函数,该函数计算斐波那契数列。为了提高性能,我们使用functools.lru_cache对该函数进行了缓存。

在路由/fibonacci/{n}中,我们调用fibonacci函数并返回结果。可以命令访问 http://localhost:8000/fibonacci/{n}进行调试。

需要注意的是 maxsize参数是functools.lru_cache装饰器的一个配置选项,它表示缓存的最大容量。lru_cache使用字典来存储缓存项,当一个新的结果需要被缓存时,它会检查当前缓存的大小。如果缓存已满(即达到maxsize),则会根据LRU策略移除最近最少使用的缓存项。如果maxsize设置为None,则缓存可以无限制地增长,这可能导致内存问题。

单元测试中的mock

Python unittest.mock

在Python中,unittest模块提供了一个名为unittest.mock的子模块,用于创建mock对象。unittest.mock包含一个名为Mock的类以及一个名为patch的上下文管理器/装饰器,可以用于替换被测试代码中的依赖项。

import requests
from unittest import TestCase
from unittest.mock import patch# 定义一个函数 get_user_name,它使用 requests.get 发起 HTTP 请求以获取用户名称
def get_user_name(user_id):response = requests.get(f"https://api.example.com/users/{user_id}")return response.json()["name"]# 创建一个名为 TestGetUserName 的测试类,它继承自 unittest.TestCase
class TestGetUserName(TestCase):# 使用 unittest.mock.patch 装饰器替换 requests.get 函数@patch("requests.get")# 定义一个名为 test_get_user_name 的测试方法,它接受一个名为 mock_get 的参数def test_get_user_name(self, mock_get):# 配置 mock_get 的返回值,使其在调用 json 方法时返回一个包含 "name": "Alice" 的字典mock_get.return_value.json.return_value = {"name": "Alice"}# 调用 get_user_name 函数,并传入 user_id 参数user_name = get_user_name(1)# 使用 unittest.TestCase 的 assertEqual 方法检查 get_user_name 的返回值是否等于 "Alice"self.assertEqual(user_name, "Alice")# 使用 unittest.mock.Mock 的 assert_called_with 方法检查 mock_get 是否被正确调用mock_get.assert_called_with("https://api.example.com/users/1")

总结

在开发测试桩时,我们需要根据实际需求和后端服务的特点来设计测试桩的行为,为的是使其更接近实际后端服务的行为,确保测试结果具有更高的可靠性和准确性。

可能还有其他的优化方案,欢迎大家提出。希望本文能对大家的工作带来帮助。

如果觉得还不错,就在右下角点个赞吧,感谢!


资料获取方法

【留言777】

各位想获取源码等教程资料的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

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

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

相关文章

/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28‘ not found

某项目中&#xff0c;我要给别人封装一个深度学习算法的SDK接口&#xff0c;运行在RK3588平台上&#xff0c;然后客户给我的交叉编译工具链是 然后我用他们给我的交叉编译工具链报下面的错误&#xff1a; aarch64-buildroot-linux-gnu-gcc --version /data/chw/aarch64/bin/cca…

使用idea实现git操作大全(在项目开发中遇到的实际情况

使用idea实现git操作大全&#xff08;在项目开发中遇到的实际情况&#xff09; 1.安装git插件2.在开发中切记拉一个自己的分支 1.安装git插件 2.在开发中切记拉一个自己的分支 选中需要拉的分支&#xff0c;右键该分支&#xff0c;选中new breach from “分支”&#xff0c;点…

Permute 3 for mac音视频格式转换

Permute是一款Mac平台上的媒体格式转换软件&#xff0c;由Chaotic Software开发。它可以帮助用户快速地将各种音频、视频和图像文件转换成所需格式&#xff0c;并提供了一些常用工具以便于用户进行编辑和处理。 Permute的主要特点包括&#xff1a; - 支持大量格式&#xff1a;支…

小程序安全性加固:如何保护用户数据和防止恶意攻击

第一章&#xff1a;引言 在当今数字化时代&#xff0c;移动应用程序的使用已经成为人们日常生活中的重要组成部分。小程序作为一种轻量级的应用程序形式&#xff0c;受到了广泛的欢迎。然而&#xff0c;随着小程序的流行&#xff0c;安全性问题也日益凸显。用户数据泄露和恶意攻…

flask中写一个基础的sqlHelper类

写一个SQLHelper类&#xff1a; from flask_sqlalchemy import SQLAlchemydb SQLAlchemy()class SQLHelper:staticmethoddef add(record):db.session.add(record)return SQLHelper.session_commit()staticmethoddef add_all(records):db.session.add_all(records)return SQLH…

STM32 DMA

DMA介绍 DMA&#xff0c;Direct Memory Access&#xff0c;即直接存储器访问。 DMA传输&#xff0c;将数据从一个地址空间复制到另一个地址空间。&#xff08;内存&#xff08;程序里定义的数组&#xff09;->外设&#xff08;串口、SPI等外设的数据寄存器&#xff09;、外…

【MySQL】DDL和DML

4&#xff0c;DDL:操作数据库 我们先来学习DDL来操作数据库。而操作数据库主要就是对数据库的增删查操作。 4.1 查询 查询所有的数据库 SHOW DATABASES; 运行上面语句效果如下&#xff1a; 上述查询到的是的这些数据库是mysql安装好自带的数据库&#xff0c;我们以后不要操…

django实现部门表的增删改查界面

1、前期准备 部署好mysql数据库&#xff0c;创建好unicom数据库下载好bootstap的插件下载好jquery的插件下载好mysqlclient-1.4.6-cp36-cp36m-win_amd64.whl的安装包&#xff0c;根据python的版本下载 2、创建项目 在pycharm中创建项目 在pycharm的终端创建虚拟环境 py -m v…

Linux知识点 -- 基础IO(三)

Linux知识点 – 基础IO&#xff08;三&#xff09; 文章目录 Linux知识点 -- 基础IO&#xff08;三&#xff09;一、理解文件系统1.磁盘文件2.文件系统的存储结构3.inode与文件名的关系 二、软硬链接1、软链接2.硬链接 三、动静态库1.库2.生成静态库3.静态库的使用4.生成动态库…

基于SpringBoot+Vue的在线考试系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Zabbix分布式监控Web监控

目录 1 概述2 配置 Web 场景2.1 配置步骤2.2 显示 3 Web 场景步骤3.1 创建新的 Web 场景。3.2 定义场景的步骤3.3 保存配置完成的Web 监控场景。 4 Zabbix-Get的使用 1 概述 您可以使用 Zabbix 对多个网站进行可用性方面监控&#xff1a; 要使用 Web 监控&#xff0c;您需要定…

matlab编程实践18、19

浅水方程 浅水方程可以建立起海啸和浴缸中波浪的数学模型。浅水方程建立了水或者其它不可压缩液体受扰动时传播的模型。隐含的假设是&#xff0c;液体的深度和波浪的长度、扰动等相比是很小的。 在这样的记号下&#xff0c;浅水方程为双曲守恒定律的一个例子。 使用拉克斯-冯特…

线段树详解 原理解释 + 构建步骤 + 代码(带模板)

目录 介绍&#xff1a; 定义&#xff1a; 以具体一个题目为例&#xff1a;​ 树的表示方法&#xff1a; 实现步骤&#xff1a; 构建结点属性&#xff1a; pushup函数&#xff1a; build函数&#xff1a; pushdown函数&#xff1a; modify函数&#xff1a; query…

『赠书活动 | 第十六期』《深入浅出Java虚拟机:JVM原理与实战》

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 『赠书活动 &#xff5c; 第十六期』 本期书籍&#xff1a;《深入浅出Java虚拟机&#xff1a;JVM原理与实战》 赠书规则&#xff1a;评论区&#xff1a;点赞&#xff…

站点可靠性工程 (SRE)

随着世界各地的组织努力开发安全、可靠、可扩展且可持续的 IT 基础架构&#xff0c;对高效基础架构监控和管理的需求日益增长&#xff0c;企业正在用不可扩展的遗留架构换取现代解决方案&#xff0c;在尖端技术的推动下&#xff0c;这些使基础设施管理过程更加顺畅和轻松&#…

SpringBoot + minio实现分片上传、秒传、续传

什么是minio MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议&#xff0c;项目地址是https://github.com/minio/minio。 引用官网&#xff1a; MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容…

C++设计模式之访问者模式

C访问者设计模式 文章目录 C访问者设计模式什么是设计模式什么是访问者设计模式该模式有什么优缺点优点缺点 如何使用 什么是设计模式 设计模式是一种通用的解决方案&#xff0c;用于解决特定的一类问题。它是一种经过验证的代码组织方式&#xff0c;可以帮助开发人员更快地实…

Linux——平台设备及其驱动

目录 前言 一、平台设备 二、平台驱动 三、平台驱动简单实例 四、 电源管理 五、udev 和驱动的自动加载 六、使用平台设备的LED 驱动 七、自动创建设备节点 前言 要满足 Linux 设备模型&#xff0c;就必须有总线、设备和驱动。但是有的设备并没有对应的物理总线&#x…

互联网被裁的程序员,未来有什么方向呢?

做了一份程序员“失业”后的自救方向汇总&#xff1a; 接下来挨个聊聊。 产品经理 都说产品和技术总是相爱相杀&#xff0c;不过产品和技术的关系也是最近的。 无论是产品转技术&#xff0c;还是技术转产品&#xff0c;相对来说都是比较容易的&#xff0c;很多底层逻辑是互通…

后端通过CorsRegistry对象配置了全局跨域,但是前端仍然报CORS跨域错误

后端通过CorsRegistry配置了全局跨域&#xff0c;但是前端仍然报CORS跨域错误 问题背景 在实现登录功能时&#xff0c;我先是通过CorsRegistry配置了全局跨域&#xff0c;然后配置了一个登录拦截器后前端就报错CORS跨域错误 问题原因 前置知识 首先我们来了解一下什么是跨域错误…