Python+Pytest实现压力测试详解

目录
  • 1.程序说明
    • 1.1 设置测试参数
    • 1.2 初始化测试结果
    • 1.3 定义测试函数
    • 1.4 创建线程、执行线程、等待
    • 1.5 计算测试结果
    • 1.6 将测试结果写入文件
  • 2.程序执行
    • 2.1 直接执行
    • 2.2 加个装饰器然后出报告
  • 3.案例缺陷
  • 4 完整源码

在现代Web应用程序中,性能是至关重要的。为了确保应用程序能够在高负载下正常运行,我们需要进行性能测试。 今天,应小伙伴的提问, 田辛老师来写一个Pytest进行压力测试的简单案例。 这个案例的测试网站我们就隐藏了,不过网站的基本情况是:

  • 阿里
  • 框架:FastAdmin.net

1.程序说明

1.1 设置测试参数

首先,田辛老师做的第一件事情就是设置测试参数。代码如下

# 定义测试用例
def test_performance():
    # 设置测试参数
    url = 'http://www.a.com/'
    num_threads = 20
    num_requests = 200
    timeout = 5

这里面,田老师设置了网站的URL, 线程数, 每个线程的请求次数,以及超时时间。 可以看到, 这里面田老师一共会做4000次请求。

1.2 初始化测试结果

这段代码我想不需要田老师多讲, 这里做一个提示:注意缩进, 这段代码仍然在测试用例test_performance内。

    # 初始化测试结果
    response_times = []
    errors = 0
    successes = 0

1.3 定义测试函数

接下来, 田老师定义了一个内部函数。这个函数就是在某一线程内完成设定次数的请求。

    # 定义测试函数
    def test_func():
        nonlocal errors, successes
        for _ in range(num_requests):
            try:
                start_time = time.time()
                requests.get(url, timeout=timeout)
                end_time = time.time()
                response_time = end_time - start_time
                response_times.append(response_time)
                successes += 1
            except requests.exceptions.RequestException:
                errors += 1

1.4 创建线程、执行线程、等待

    # 创建测试线程
    threads = []
    for _ in range(num_threads):
        t = threading.Thread(target=test_func)
        threads.append(t)  

    # 启动测试线程
    for t in threads:
        t.start()  

    # 等待测试线程结束
    for t in threads:
        t.join()

1.5 计算测试结果

    # 计算测试结果
    total_requests = num_threads * num_requests
    throughput = successes / (sum(response_times) or 1)
    concurrency = num_threads
    error_rate = errors / (total_requests or 1)
    cpu_usage = psutil.cpu_percent()
    memory_usage = psutil.virtual_memory().percent

1.6 将测试结果写入文件

    # 将测试结果写入文件
    with open('performance_test_result.txt', 'w') as f:
        f.write(f'总请求数:{total_requests}\n')
        f.write(f'总时间:{sum(response_times):.2f}s\n')
        f.write(f'吞吐量:{throughput:.2f} requests/s\n')
        f.write(f'并发数:{concurrency}\n')
        f.write(f'错误率:{error_rate:.2%}\n')
        f.write(f'CPU利用率:{cpu_usage:.2f}%\n')
        f.write(f'内存利用率:{memory_usage:.2f}%\n')

2.程序执行

2.1 直接执行

在PyCharm里面直接执行这段代码, 得出的结果是:

总请求数:4000  
总时间:1837.65s  
吞吐量:2.17 requests/s  
并发数:20  
错误率:0.12%  
CPU利用率:4.10%  
内存利用率:88.60%

2.2 加个装饰器然后出报告

如果在PyCharm里面直接执行上面的代码, 虽然我们把结果写在文件中,但是, 不好看呀。

所以呢,田老师再额外介绍一个方法,这个方法能够生成一个相对美观的测试报告出来。

2.2.1 声明压力测试

首先在定义用例的时候通过装饰器声明这是一个压力测试:

# 定义测试用例
@pytest.mark.performance
def test_performance():
    # 设置测试参数
    url = 'http://www.a.biz/'
    num_threads = 20

2.2.2 在命令行中通过pytest命令执行测试

第二步, 在命令行中执行测试

  • -v 用于显示详细的测试结果
  • --html 用于指定输出报告的位置。 这个参数需要依赖包:pytest-html

$ pytest  -v --html=report.html  test_a.py

输出执行结果是:

======================== test session starts =================================
platform win32 -- Python 3.10.9, pytest-7.2.1, pluggy-1.0.0 -- D:\python-grp\miniconda_env\py3.10_playwright\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.10.9', 'Platform': 'Windows-10-10.0.22624-SP0', 'Packages': {'pytest': '7.2.1', 'pluggy': '1.0.0'}, 'Plugins': {'allure-pytest': '2.12.0', 'base-url': '2.0.0', 'html': '3.2.0', 'metadata': '2.0.4', 'ordering': '0.6', 'playwright': '0.3.0'}, 'JAVA_HOME': 'D:\\java-grp\\jdk\\', 'Base URL': ''}
rootdir: E:\develop\python\pytest-training\test
plugins: allure-pytest-2.12.0, base-url-2.0.0, html-3.2.0, metadata-2.0.4, ordering-0.6, playwright-0.3.0
collected 1 item

test_a.py::test_performance PASSED                                                                                                                                 [100%]

========================== warnings summary ================================= 
test_a.py:25
  E:\develop\python\pytest-training\test\test_a.py:25: PytestUnknownMarkWarning: Unknown pytest.mark.performance - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.performance

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
-- generated html file: file:///E:/develop/python/pytest-training/test/report.html -- 
================= 1 passed, 1 warning in 99.09s (0:01:39) ===================

(D:\python-grp\miniconda_env\py3.10_playwright) E:\develop\python\pytest-training\test>

最终生成的报告是:(有点长, 截取了关键部分)

3.案例缺陷

因为时间关系, 本案例今天没有时间在服务器端执行, 所以通过psutil库所取得CPU利用率和内存利用率时间并不对。 如果是在服务器端执行, 这两个数字才是对的。

如果要在本地获取服务器的CPU,内存,IO等情况,有一个监控神器:Prometheus。不过这东西配置起来又是另一个话题, 且听后话~哈哈(55555, 好像,又刨了一个坑)

4 完整源码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
#-----------------------------------------------------------------------------
#                     --- TDOUYA STUDIOS ---
#-----------------------------------------------------------------------------
#
# @Project : pytest-training
# @File    : test_a.py
# @Author  : tianxin.xp@gmail.com
# @Date    : 2023/3/10 14:39
#
# 压力测试案例
#
#--------------------------------------------------------------------------"""
import threading
import time  

import psutil
import pytest
import requests  

# 定义测试用例
@pytest.mark.performance
def test_performance():
    # 设置测试参数
    url = 'http://www.tdouya.biz/'
    num_threads = 20
    num_requests = 200
    timeout = 5  

    # 初始化测试结果
    response_times = []
    errors = 0
    successes = 0  

    # 定义测试函数
    def test_func():
        nonlocal errors, successes
        for _ in range(num_requests):
            try:
                start_time = time.time()
                requests.get(url, timeout=timeout)
                end_time = time.time()
                response_time = end_time - start_time
                response_times.append(response_time)
                successes += 1
            except requests.exceptions.RequestException:
                errors += 1  

    # 创建测试线程
    threads = []
    for _ in range(num_threads):
        t = threading.Thread(target=test_func)
        threads.append(t)  

    # 启动测试线程
    for t in threads:
        t.start()  

    # 等待测试线程结束
    for t in threads:
        t.join()  

    # 计算测试结果
    total_requests = num_threads * num_requests
    throughput = successes / (sum(response_times) or 1)
    concurrency = num_threads
    error_rate = errors / (total_requests or 1)
    cpu_usage = psutil.cpu_percent()
    memory_usage = psutil.virtual_memory().percent  

    # 输出测试结果
    print(f'总请求数:{total_requests}')
    print(f'总时间:{sum(response_times):.2f}s')
    print(f'吞吐量:{throughput:.2f} requests/s')
    print(f'并发数:{concurrency}')
    print(f'错误率:{error_rate:.2%}')
    print(f'CPU利用率:{cpu_usage:.2f}%')
    print(f'内存利用率:{memory_usage:.2f}%')  

    # 将测试结果写入文件
    with open('performance_test_result.txt', 'w') as f:
        f.write(f'总请求数:{total_requests}\n')
        f.write(f'总时间:{sum(response_times):.2f}s\n')
        f.write(f'吞吐量:{throughput:.2f} requests/s\n')
        f.write(f'并发数:{concurrency}\n')
        f.write(f'错误率:{error_rate:.2%}\n')
        f.write(f'CPU利用率:{cpu_usage:.2f}%\n')
        f.write(f'内存利用率:{memory_usage:.2f}%\n')

到此这篇关于Python+Pytest实现压力测试详解的文章就介绍到这了,更多相关Python Pytest压力测试内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python实现websocket的客户端压力测试

    使用python进行websocket的客户端压力测试,这个代码是从github上 找到.然后简单修改了下.大神运用了进程池,以及线程池的内容.所以保存下来,学习学习 然后需要说明的是:本次用的python2.7,也尝试用python3.6,但是老实出现websocket-client包和python3不能兼容的情况,提示没有相关的方法.所以不得已最后又采用了python2 # -*- coding:utf-8 -*- # __author__ == 'chenmingle' import we

  • python单元测试框架pytest介绍

    pytest是python语言中一款强大的单元测试框架,用来管理和组织测试用例,可应用在单元测试.自动化测试工作中. unittest也是python语言中一款单元测试框架,但是功能有限,没有pytest灵活. 就像:苹果电脑mac air和mac pro一样.都是具备同样的功能,但是好用,和更好用. 本文包含以下几个内容点: 1)pytest的简单示例 2)pytest的安装 3)pytest的特征.与unittest的区别. 4) pytest如何自动识别用例. 5)pytest框架中,用例

  • Python测试框架pytest介绍

    目录 一.Pytest简介 二.Pytest安装 三.Pytest测试执行 四.测试类主函数 五.断言方法 六.常用命令详解 七.接口调用 一.Pytest简介 Pytest is a mature full-featured Python testing tool that helps you write better programs.The pytest framework makes it easy to write small tests, yet scales to support

  • Python实现的多线程http压力测试代码

    本文实例讲述了Python实现的多线程http压力测试代码.分享给大家供大家参考,具体如下: # Python version 3.3 __author__ = 'Toil' import sys, getopt import threading def httpGet(url, file): import http.client conn = http.client.HTTPConnection(url) conn.request("GET", file) r = conn.getr

  • python多线程http压力测试脚本

    本文实例为大家分享了python多线程http压力测试的具体代码,供大家参考,具体内容如下 #coding=utf-8 import sys import time import thread import httplib, urllib import random import uuid import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d

  • Python+Pytest实现压力测试详解

    目录 1.程序说明 1.1 设置测试参数 1.2 初始化测试结果 1.3 定义测试函数 1.4 创建线程.执行线程.等待 1.5 计算测试结果 1.6 将测试结果写入文件 2.程序执行 2.1 直接执行 2.2 加个装饰器然后出报告 3.案例缺陷 4 完整源码 在现代Web应用程序中,性能是至关重要的.为了确保应用程序能够在高负载下正常运行,我们需要进行性能测试. 今天,应小伙伴的提问, 田辛老师来写一个Pytest进行压力测试的简单案例. 这个案例的测试网站我们就隐藏了,不过网站的基本情况是:

  • .net core如何利用ConcurrentTest组件对方法进行压力测试详解

    前言 工欲善其事,必先利其器!在编写服务中首先要有一个好的测试工具,在dontecore下性能测试有BenchmarkDotNet,只需要简单的配置一下就可以对方法的性能进行详细的测试.但有时候需要对不同并发下看其处理效率和延时统计查看,如HTTP服务对应着大量的测试工具如ab,bombardier等等.由于找不到类似于测试HTTP服务的工具来测试代码用例,于时就有了ConcurrentTest这个组件的实现.通过ConcurrentTest组件可以运行不同的测试用例,并可以实时查看具体的并发情

  • python pytest进阶之fixture详解

    前言 学pytest就不得不说fixture,fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unittest是没什么区别的(个人理解). fixture用途 1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现 2.测试用例的前置条件可以使用fixture实现 3.支持经典的xunit fixture ,像unittest使用的setup和te

  • Python测试框架pytest核心库pluggy详解

    目录 代码案例 实例化: 添加到钩子定义中 (add_hookspecs) 注册插件 register 运行插件 pm.hook.myhook 代码案例 import pluggy # HookspecMarker 和 HookimplMarker 实质上是一个装饰器带参数的装饰器类,作用是给函数增加额外的属性设置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("m

  • python+adb+monkey实现Rom稳定性测试详解

    我为什么做这项工作? 其实这项工作是另一位同事在做,过程中发下了一些问题,但是种种原因log和数据都没有收集到,无法进行分析.然后我就接手了,负责复现她发现的问题并提供log和数据给开发分析. 需要测试的是一个什么样的功能? 需求是这样的:开发在Framework层增加了app应用权限管控(Android11中基本权限.自动以权限.AIDL),服务端可以通过下发指令到手机,控制app可以访问及不能访问的权限.同时安装app也需要对签名做校验. 该如何开始这项工作呢? 不用多言,自动化是必须的,但

  • 通过Python实现一个A/B测试详解

    目录 / 01 / AB测试 / 02 / 使用Python进行AB测试 / 03 / 数据准备 / 04 / AB测试找到最佳营销策略 / 05 / 结论 A/B测试,通过分析两种不同的营销策略,以此来选择最佳的营销策略,可以高效地将流量转化为销售额(或转化为你的预期目标). 有助于找到更好的方法来寻找客户.营销产品.扩大影响范围或将目标客户转化为实际客户. A/B测试是每个学习数据分析同学,都应该知道且去学习的概念. / 01 / AB测试 举个例子,我在短视频App上购买流量推广我的视频(

  • 对python 自定义协议的方法详解

    前面说到最近在写python的一些东西,然后和另外一位小伙伴定义了协议,然后昨天我有一部分东西没理解对,昨天上午我自己重写了一遍接收和发送的全部逻辑,昨天下午补了压力测试的脚本,自测没问题之后告知联调的小伙伴. 结果上午还是出了一点问题,然后我们两对代码,他写了一个python的实现.还好最后我这边没问题.(我也害怕是我这边出问题啊,所以我自己的代码都自己检查了好几遍) 简单放一下他的实现: import struct import ctypes class E(Exception): def

  • python魔法方法-自定义序列详解

    自定义序列的相关魔法方法允许我们自己创建的类拥有序列的特性,让其使用起来就像 python 的内置序列(dict,tuple,list,string等). 如果要实现这个功能,就要遵循 python 的相关的协议.所谓的协议就是一些约定内容.例如,如果要将一个类要实现迭代,就必须实现两个魔法方法:__iter__.next(python3.x中为__new__).__iter__应该返回一个对象,这个对象必须实现 next 方法,通常返回的是 self 本身.而 next 方法必须在每次调用的时

  • python魔法方法-属性访问控制详解

    属性访问控制 所谓的属性访问控制就是控制点号访问属性的行为,而且不仅是类的外部,连类的内部也受控制,代码见真章,边看代码边解释: •__getattr__(self, item) 定义当访问不存在的属性时的行为,注意是不存在的属性. class Foo(object): def __init__(self, value): self.value = value def __getattr__(self, item): print item # 查看得到的参数是什么 print type(item

  • Python实现的rsa加密算法详解

    本文实例讲述了Python实现的rsa加密算法.分享给大家供大家参考,具体如下: 算法过程 1. 随意选择两个大的质数p和q,p不等于q,计算N=pq. 2. 根据欧拉函数,不大于N且与N互质的整数個数為(p-1)(q-1). 3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1). 4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1)). 5. 将p和q的记录销毁. (N,e)是公钥,(N,d)是私钥. python代码 # -*- coding

随机推荐