python单链路性能测试实践

目录
  • 引言
  • 场景思路
    • 场景
    • 思路
  • Demo实现
  • 控制台输出

引言

在经历过一些尝试之后,觉得在当下的项目中运用链路压测的能力,不等着其他人了。

链路这个词其实不如路径通俗易懂,跟产品沟通这个比较有效率。具体的操作路径,产品会给一份出来,但是这都是基于UI和产品思维的文档,跟接口测试区别还是很大的,只能提供参考依据。

需要端上测试协作,有些业务细节还得端上测试同学帮忙补充一下。还需要运维同事帮忙理一下各个接口的请求量比例,这次的比例我是依据灵光一现写出来,然后大家一起调整的。

本次由于比较初级,所以这块文档就不写出来了,放一个图来表达一下这个链路做了些什么,PS:我现在很喜欢用图而不是文字,沟通效率太高了。推荐工具draw.io,感兴趣的可以参考文末的热文中两张架构图中的介绍。

资源库1.4链路压测方案

这次把登录剔除了,因为太慢了,对测试结果影响比较大。

场景思路

场景

场景就是老师登录,首先会请求一个知识点列表,然后通过知识点属性筛选推荐课程列表,在对课程列表中的数据进行收藏和取消收藏,在获取自己当前知识点下的课程列表(包含原创和收藏)。

思路

本次依然采取固定线程的压测模型,本人预估线程200左右,测试用户600备用,列表页保证2页数据。

每个线程绑定一个用户,然后用户开始循环链路执行步骤,执行一次当做一次Q。单次Q包含9HTTP接口请求(放弃了Socket接口,以后有需求再添加Socket接口到链路中),其中3次修改操作,6次查询操作。

具体的逻辑通过内部静态类实现,然后多一个K类,用来存储每次获取的知识点属性,方便调用。由于接口请求方法都是用基础数据类型和String作为参数,所以调用时候会显得有点啰嗦。但无伤大雅,脚本写出来,本来就是用完就扔到仓库里面,改天再用再优化。

Demo实现

package com.okayqa.composer.performance.resource1_4
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.funtester.base.bean.AbstractBean
import com.funtester.base.constaint.ThreadLimitTimesCount
import com.funtester.frame.execute.Concurrent
import com.funtester.httpclient.ClientManage
import com.funtester.utils.ArgsUtil
import com.okayqa.composer.base.OkayBase
import com.okayqa.composer.function.Mirro
import com.okayqa.composer.function.OKClass
class Login_collect_uncollect extends OkayBase {
    public static void main(String[] args) {
        ClientManage.init(10, 5, 0, "", 0)
        def util = new ArgsUtil(args)
        def thread = util.getIntOrdefault(0, 30)
        def times = util.getIntOrdefault(1, 40)
        def tasks = []
        thread.times {
            tasks << new FunTester(it, times)
        }
        new Concurrent(tasks, "资源库1.4登录>查询>收藏>取消收藏链路压测").start()
        allOver()
    }
    private static class FunTester extends ThreadLimitTimesCount<Integer> {
        OkayBase base
        def mirro
        def clazz
        FunTester(Integer integer, int times) {
            super(integer, times, null)
        }
        @Override
        void before() {
            super.before()
            base = getBase(t)
            mirro = new Mirro(base)
            clazz = new OKClass(base)
        }
        @Override
        protected void doing() throws Exception {
        
            def klist = mirro.getKList()</code><code>            mirro.getKList()
            def karray = klist.getJSONArray("data")
            K ks
            karray.each {
                JSONObject parse = JSON.parse(JSON.toJSONString(it))
                if (ks == null) {
                    def level = parse.getIntValue("node_level")
                    def type = parse.getIntValue("ktype")
                    def id = parse.getIntValue("id")
                    ks = new K(id, type, level)
                }
            }
            JSONObject response = clazz.recommend(ks.id, ks.type, ks.level)</code><code>            clazz.recommend(ks.id, ks.type, ks.level)            clazz.recommend(ks.id, ks.type, ks.level)
            def minis = []
            int i = 0
            response.getJSONArray("data").each {
                if (i++ &lt; 2) {
                    JSONObject parse = JSON.parse(JSON.toJSONString(it))
                    int value = parse.getIntValue("minicourse_id")
                    minis &lt;&lt; value
                }
            }
            clazz.unCollect(random(minis))
            mirro.getMiniCourseListV3(ks.id, ks.type, 0, ks.level)            mirro.getMiniCourseListV3(ks.id, ks.type, 0, ks.level)
        }
    }
    private static class K extends AbstractBean {
        int id
        int type
        int level
        K(int id, int type, int level) {
            this.id = id
            this.type = type
            this.level = level
        }
    }
}

其中AbstractBean类是一个抽象类,用于一些bean的方法封装,就是为了省事儿。

package com.funtester.base.bean
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.funtester.frame.Save
import com.funtester.frame.SourceCode
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.BeanUtils
/**
 * bean的基类
 */
abstract class AbstractBean {
    static final Logger logger = LoggerFactory.getLogger(AbstractBean.class)
    /**
     * 将bean转化为json,为了进行数据处理和打印
     *
     * @return
     */
    JSONObject toJson() {
        JSONObject.parseObject(JSONObject.toJSONString(this))
    }
    /**
     * 文本形式保存
     */
    def save() {
        Save.saveJson(this.toJson(), this.getClass().toString() + SourceCode.getMark());
    }
    /**
     * 控制台打印,使用WARN记录,以便查看
     */
    def print() {
        logger.warn(this.getClass().toString() + ":" + this.toString());
    }
    def initFrom(String str) {
        JSONObject.parseObject(str, this.getClass())
    }
    def initFrom(Object str) {
        initFrom(JSON.toJSONString(str))
    }
    def copyFrom(AbstractBean source) {
        BeanUtils.copyProperties(source, this)
    }
    def copyTo(AbstractBean target) {
        BeanUtils.copyProperties(this, target)
    }
    /**
     * 这里bean的属性必需是可以访问的,不然会返回空json串
     * @return
     */
    @Override
    String toString() {
        JSONObject.toJSONString(this)
    }
    @Override
    protected Object clone() {
        initFrom(this)
    }
}

控制台输出

~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
>  {
>  ① . "rt":1665,
>  ① . "total":1188,
>  ① . "qps":18.018,
>  ① . "failRate":0.0,
>  ① . "threads":30,
>  ① . "startTime":"2021-02-24 16:57:23",
>  ① . "endTime":"2021-02-24 16:58:34",
>  ① . "errorRate":1.01,
>  ① . "executeTotal":1188,
>  ① . "mark":"资源库1.4登录>查询>收藏>取消收藏链路压测241657",
>  ① . "table":"eJzj5VLAD15sbXm2a8LTXZMN9Uyez9z9dO9Uu2fzl75Yv8ju2ZRtL6b32z3tn/ZsWweE83Lyvhfb1z/t6362tZvT2EChJKMoNaWYgA0KvFy8+F0RlFpckJ9XnKoQkpmbaqVQoVucWpSZmKOQV5qro1Cpm5uakpmYR8gOQq5QyM3MU4AYZWVhYqmQW6yTm1hhZWxoaQxkE9RNjA2UgEfTOoBo1JZRW2hmRSsQ0ccmsBW0tgnVQzS1DatVtLMRn3W0sPXRtCYgAlLtQITXWura/mhaMxCRYC+VXUGyv2nhmkfTGoGI0rCgrsseTWsBImLSIZ1dCA8sOjmMXNfCU9ZAupNYV8MdC4106qdA2vkAniAGq6OJ8AlVi6GB99FgSvTU8BU8egaBg6jsO3iWHwSuoZUPB4EzRn046sNRHw68M0Z9OOrDEe5DABkr1eo="
>  }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~

以上就是python单链路性能测试实践的详细内容,更多关于python单链路性能测试的资料请关注我们其它相关文章!

(0)

相关推荐

  • python性能测试手机号验证码登录压测示例详解

    目录 引言 业务逻辑: 基本的校验规则如下: 解决方案: 测试方案: 压测脚本: 模块类方法: 引言 这两天遭遇了手机号登录相关的压测需求,算是比较棘手的.主要原因有两个,第一:之前从来没有接手过这个项目,不熟悉各种规则:第二:数据量偏大,需要开发配合协调校验规则. 业务逻辑: 请求发送验证码接口,发送成功(已绑定的手机号,且有效的用户状态)可以获取到登录的一个参数traceNo 使用traceNo.短信验证码.手机号请求登录接口 基本的校验规则如下: 手机号校验,排除一些不存在的号段,11位数

  • python性能测试对手机号绑定进行压测

    目录 引言 业务逻辑: 基本的校验规则如下: 解决方案: 测试方案: 压测脚本: 模块类方法: 引言 最近遭遇了绑定手机号相关的压测需求,有了手机号登录的经验和测试数据,这次算起来比较简单.最重要的是难点就是要求开发配合调整配置已经在上一期文章:手机号验证码登录性能测试中问题解决了,绑定手机号唯一的难点就是如何在单账号绑定的过程中不断切换手机号,而且保证最后账号的绑定手机号还是一开始的14+uid的模式. 业务逻辑: 请求发送验证码接口,发送成功(未绑定的手机号,用户登录状态)可以获取到登录的一

  • 利用python进行接口测试及类型介绍

    目录 前言 接口测试的坑 接口类型 快速上手接口测试 接口文档分析 编写接口用例 执行接口测试 前言 其实我觉得接口测试很简单,比一般的功能测试还简单(这话我先这样说,以后可能会删O(∩_∩)O哈!),现在找工作好多公司都要求有接口测试经验,也有好多人问我(也就两三个人)什么是接口测试,本着不懂也要装懂的态度,我会说:所谓接口测试就是通过测试不同情况下的入参与之相应的出参信息来判断接口是否符合或满足相应的功能性.安全性要求. 我为啥说接口测试比功能测试简单呢,因为功能测试是从页面输入值,然后通过

  • Python Flask 上传文件测试示例

    目录 Flask file upload代码 上传测试 上传临时文件 使用 tempfile 使用 StringIO 其他 Flask file upload代码 import os from flask import Flask, request, redirect, url_for, send_from_directory from werkzeug.utils import secure_filename UPLOAD_FOLDER = '/tmp/flask-upload-test/'

  • python接口测试对修改密码接口进行压测

    目录 引言 测试脚本代码 usercenter主要代码 okaybase主要代码 引言 做接口测试中,对于一般性的单业务接口测试很多工具可供选择,但是对于一些相关业务相关性的关联接口测试就比较麻烦,使用工具比如jmeter.postman.soapui等等就比较麻烦. 我比较偏重脚本化执行测试用例,所以选择了groovy作为主要语言来进行接口测试,但是脚本依赖的库还是基于之前所在的java为主的测试框架,有兴趣的可以翻翻以前的文章. 项目的架构思路是以模块为基础把接口分类,然后对于接口的请求单独

  • python自动化测试之破解滑动验证码

    在Web自动化测试的过程中,经常会被登录的验证码给卡住,不知道如何去通过验证码的验证.一般的情况下遇到验证码我们可以都可以找开发去帮忙解决,关闭验证码,或者给一个万能的验证码!那么如果开发不提供帮助的话,我们自己有没有办法来处理这些验证码的问题呢?答案当然是有的,常见的验证码一般分为两类,一类是图文验证码,一类是滑动验证码! 滑动验证破解思路 关于滑动验证码破解的思路大体上来讲就是以下两个步骤: 1.获取滑块滑动的距离 2.模拟拖动滑块,通过验证. 关于这种滑动的验证码,滑块和缺口背景都是分别是

  • python单链路性能测试实践

    目录 引言 场景思路 场景 思路 Demo实现 控制台输出 引言 在经历过一些尝试之后,觉得在当下的项目中运用链路压测的能力,不等着其他人了. 链路这个词其实不如路径通俗易懂,跟产品沟通这个比较有效率.具体的操作路径,产品会给一份出来,但是这都是基于UI和产品思维的文档,跟接口测试区别还是很大的,只能提供参考依据. 需要端上测试协作,有些业务细节还得端上测试同学帮忙补充一下.还需要运维同事帮忙理一下各个接口的请求量比例,这次的比例我是依据灵光一现写出来,然后大家一起调整的. 本次由于比较初级,所

  • python单链表实现代码实例

    链表的定义:链表(linked list)是由一组被称为结点的数据元素组成的数据结构,每个结点都包含结点本身的信息和指向下一个结点的地址.由于每个结点都包含了可以链接起来的地址信息,所以用一个变量就能够访问整个结点序列.也就是说,结点包含两部分信息:一部分用于存储数据元素的值,称为信息域:另一部分用于存储下一个数据元素地址的指针,称为指针域.链表中的第一个结点的地址存储在一个单独的结点中,称为头结点或首结点.链表中的最后一个结点没有后继元素,其指针域为空. python单链表实现代码: 复制代码

  • Python 3.6 性能测试框架Locust安装及使用方法(详解)

    背景 Python3.6 性能测试框架Locust的搭建与使用 基础 python版本:python3.6 开发工具:pycharm Locust的安装与配置 点击"File"→"setting" 点击"setting",进入设置窗口,选择"Project Interpreter" 点击"+" 输入需要"Locust",点击"Install Package" 安装完成

  • python 写一个性能测试工具(一)

    国庆重新学习了一下go的gin高性能测试框架. 用JMeter来测试gin与flask接口的性能,差别很大. 为什么我自己不尝试写一个性能工具,性能工具的核心就是 并发 和 请求. 请求可以选择Python的requests库. 并发可以通过python的 进程.线程.协程模拟. 这么一想,也不是很难了,上手撸一个. 依赖库 requests==2.22.0 gevent==20.9.0 numpy==1.19.2 requests 大家并不陌生,HTTP请求库. gevent是python协程

  • python软件测试Jmeter性能测试JDBC Request(结合数据库)的使用详解

    JDBC Request 这个 Sampler 可以向数据库发送一个 jdbc 请求(sql 语句),并获取返回的数据库数据进行操作.它 经常需要和 JDBC Connection Configuration 配置原件(配置数据库连接的相关属性,如连接名.密码 等)一起使用. 1.本文使用的是 mysql 数据库进行测试 数据库的用户名为 root,用户名密码为 *********(看个人数据库用户名和密码填写) 2.数据库中有表:test,表的数据结构如下: 表中数据如下: select *

  • 基于Python的EasyGUI学习实践

    01_msgbox # 使用easygui功能,可以直接导入easygui模块 import easygui # 需要弹框时,要使用easygui. # msgbox(m)方法,输出带有m内容的信息框. # msg = message . easygui.msgbox('你好,我是easygui模块.') easygui.msgbox('今天也是充满希望的一天!') # easygui.msgbox(m,t,b)有三个参数. # m是显示的信息messag,t是信息框的标题tittle,b是信息

  • 详解Python 2.6 升级至 Python 2.7 的实践心得

    前言 CentOS 6.8 安装 Python 2.7.13,因为软件版本上的需求所以考虑将 Python 升级至 2.7.13,加上生产环境还是以 RHEL 6 为主,互联网自动化运维平台大多数也推荐以Python 2.7.x + CentOS 6.x 来操作,选择 Python 2 还是 Python 3 也没有定论,找到适合的搭配即可. 简单安装 因为Python 2.7.13以后版本会自动完善yum配置,所以不必参考以前的网上文章去修改其他地方 # 查看当前系统中的 Python 版本,

  • Python使用ClickHouse的实践与踩坑记录

    目录 1. 关于ClickHouse使用实践 1.1. ClickHouse 应用于数据仓库场景 1.2. 客户端工具DBeaver 1.3. 大数据应用实践 2. Python使用ClickHouse实践 2.1. ClickHouse第三方Python驱动clickhouse_driver 2.2. 实践程序代码 3. 小结一下 操作ClickHouse删除指定数据 ClickHouse是近年来备受关注的开源列式数据库(DBMS),主要用于数据联机分析(OLAP)领域,于2016年开源.目前

  • python从入门到实践之字典

    目录 字典概述 字典定义 查找字典的值 给字典增加键值对 给字典修改键值对的值 给字典删除键值对 字典中可以包含列表值 列表中可以包含字典 字典中可以包含字典 关于字典的一些其他操作函数和方法 len()函数 max()函数 min()函数 dict()函数 keys()方法 values()方法 items()方法 总结 字典概述 字典是一个映射集合,他储存的是键值对,通过键来查找值,而不是索引 字典定义 通过大括号{}与键值对来表示一个字典 字典名={键1:值1,键2:值2.......}

  • linux 下实现python多版本安装实践

    使用pythonbrew 复制代码 代码如下: easy_install pythonbrew [root@li637-23 schirm]# pythonbrew_install Well-done! Congratulations! The pythonbrew is installed as: /root/.pythonbrew Please add the following line to the end of your ~/.bashrc [[ -s "$HOME/.pythonbr

随机推荐