链路性能测试中参数多样性方法分享

news2024/9/24 21:27:15

目录

业务无关量

随机数字

线程安全随机

随机字符串

业务相关量

随机相关量

上游接口获取

上游接口造数据

提前造数据

总结:


下面分享几种我工作中常用到的增加参数多样性的方法。

业务无关量

这个是最常用到的,当部分的接口参数对接下来的用例没有实际影响的时候我通常会用一个随机的数字和字符串来设置参数。

随机数字

这个相对简单,我是Java,分享一下简单的代码:

    /**
     * 获取随机数,获取1~num 的数字,包含 num
     *
     * @param num 随机数上限
     * @return 随机数
     */
    public static int getRandomInt(int num) {
        return random.get().nextInt(num) + 1;
    }

    /**
     * 随机范围int,取头不取尾
     *
     * @param start
     * @param end
     * @return
     */
    public static int getRandomIntRange(int start, int end) {
        if (end <= start) return TEST_ERROR_CODE;
        return random.get().nextInt(end - start) + start;
    }

线程安全随机

在做性能测试的时候,我经常会有在不同线程随机出某个唯一的量的需求,这里我一般采用两段组成:多线程唯一量线程内唯一量

举个例子来讲:

/**
 * 用于非单纯的http请求以及非HTTP请求,没有httprequestbase对象的标记方法,自己实现的虚拟类,可用户标记header固定字段或者随机参数,使用T作为参数载体,目前只能使用在T为string类才行
 */
public class ParamMark extends SourceCode implements MarkThread, Cloneable, Serializable {

    private static final long serialVersionUID = -5532592151245141262L;

    public static AtomicInteger threadName = new AtomicInteger(getRandomIntRange(1000, 9000));

    /**
     * 用于标记执行线程
     */
    String name;

    int num = getRandomIntRange(100, 999) * 1000;

    @Override
    public String mark(ThreadBase threadBase) {
        return name + num++;
    }

    @Override
    public ParamMark clone() {
        ParamMark paramMark = new ParamMark();
        return paramMark;
    }

    public ParamMark() {
        this.name = threadName.getAndIncrement() + EMPTY;
    }

    public ParamMark(String name) {
        this();
        this.name = name;
    }


}

这里我用了一个全局的静态变量threadName作为一个基础值,之所以这里也随机是想让每次运行的时候尽量都不一样,没有使用时间戳是因为时间戳太长了,现在这个比较满足需求。

 

下面每个对象创建的时候调用的构造方法:

    public ParamMark() {
        this.name = threadName.getAndIncrement() + EMPTY;
    }

这里就可以保证每一个线程拿到的值都是不一样的,当然这个功能还可以通过中提到的方法解决,这里就不多说了。

    @Override
    public String mark(ThreadBase threadBase) {
        return name + num++;
    }

这里我就可以通过num++获取一个线程内的唯一数字,然后和name组合成为一个全局唯一的量。

随机字符串

这个好像没有特别大的需求量,之前写过一个StringUtil的工具类来完成,一般为了生成一个固定长度的随机字符串,我都是调用一个方法:

    /**
     * 获取随机字符串
     * @param i
     * @return
     */
    static String getString(int i) {
        def re = new StringBuffer()
        if (i < 1) return re
        for (int j in 1..i) {
            re.append(getChar())
        }
        re.toString()
    }

或者:

    /**
     * 获取随机字符串,没有数字
     * @param i
     * @return
     */
    static String getStringWithoutNum(int i) {
        def re = new StringBuffer()
        if (i < 1) return re
        for (int j in 1..i) {
            re << getWord()
        }
        re.toString()
    }

同样这里也有线程安全的问题,可以采用上面的多线程唯一量线程内唯一量的方式解决。如果是的唯一性要求严格的话,我一般采用时间戳的形式。这样做比较方便,如果毫秒的时间错不足以满足需求,可以采用纳秒的时间戳,自测完全没问题。

    /**
     * 获取纳秒的时间标记
     *
     * @return
     */
    public static long getNanoMark() {
        return System.nanoTime();
    }

业务相关量

这里分享一下,业务相关的参数相关的多样性问题我的解决方案。

随机相关量

这个主要场景指的是有指定的随机范围,比如说某个接口数值型参数的范围是0-7,那么我们就可以通过随机这个参数来丰富该接口的请求参数。

有的接口几个参数是关联性的,我们就需要从一个List中随机或者是数组中随机出一个对象,FunTester通常会把多个关联参数封装成一个对象,例如:

    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
        }
    }

这样我们就可以通过将可用的参数放到一个列表中获取,此方法跟下面的造数据有些区别,一个取是访问一下,一个取是取走了,各位可以待会对比一下。

分享一些代码片段:

        params.put("pullnew", random(1, 2, 3));
        params.put("class_id", random(Common.CLASSES));

其中public static final Integer[] CLASSES = property.getIntArray("classes");

 

实现方法:

    /**
     * 随机选择某一个值
     *
     * @param fs
     * @param <F>
     * @return
     */
    public static <F extends Number> F random(F... fs) {
        return fs[getRandomInt(fs.length) - 1];
    }

    /**
     * 随机选择某一个字符串
     *
     * @param fs
     * @return
     */
    public static String random(String... fs) {
        if (ArrayUtils.isEmpty(fs)) ParamException.fail("数组不能为空!");
        return fs[getRandomInt(fs.length) - 1];
    }

    /**
     * 随机选择某一个对象
     *
     * @param list
     * @param <F>
     * @return
     */
    public static <F extends Object> F random(List<F> list) {
        if (list == null || list.isEmpty()) ParamException.fail("数组不能为空!");
        return list.get(getRandomInt(list.size()) - 1);
    }
  • 如果是Groovy来写,可以用0..10来选择随机数字范围。

上游接口获取

例如JSONObject response = clazz.recommend(ks.id, ks.type, ks.level)这个接口请求中,用到的K对象是从上游接口def klist = mirro.getKList()中获取的,所有可用的K对象都在接口中返回。

如果想丰富clazz.recommend()方法的请求参数的话,一定要将mirro.getKList()中的响应结果解析成List<K>的形式。

因为多层结构,我只解析了第一层的。

            def karray = klist.getJSONArray("data")
            def kss = []
            karray.each {
                JSONObject parse = JSON.parse(JSON.toJSONString(it))
                def level = parse.getIntValue("node_level")
                def type = parse.getIntValue("ktype")
                def id = parse.getIntValue("id")
                kss << new K(id, type, level)
            }

这里我没有提前将所以可用的参数都存起来,原因有二:用户不会这么做;数据可能会变动。我提到无数据驱动,这就是个例子,不给用例输入除账号密码外的数据。

            K ks = kss.get(0)
            K ks2 = kss.get(1)
            K ks3 = kss.get(3)
            clazz.recommend(ks3.id, ks3.type, ks3.level)
            clazz.recommend(ks2.id, ks2.type, ks2.level)
            JSONObject response = clazz.recommend(ks.id, ks.type, ks.level)

上游接口造数据

这个比如收藏和取消收藏接口,正常来讲,首页可以收藏和取消收藏。在获取个人列表页可以取消收藏。这里我设置了先收藏,再去个人列表页,然后取消收藏。

这样既保证正常业务流程下,最后取消接口的是有足够的可用接口的。

            JSONObject response = clazz.recommend(ks.id, ks.type, ks.level)
            def minis = []
            int i = 0
            response.getJSONArray("data").each {
                if (i++ < 2) {
                    JSONObject parse = JSON.parse(JSON.toJSONString(it))
                    int value = parse.getIntValue("minicourse_id")
                    clazz.collect(value, ks.type, ks.id)
                }
            }
            mirro.getMiniCourseListV3(ks.id, ks.type, 0, ks.level)
            def res = mirro.getMiniCourseListV3(ks.id, ks.type, 0, ks.level)
            res.getJSONObject("data").getJSONArray("minicourse_list").each {
                def ss = JSON.parseObject(JSON.toJSONString(it))
                def mid = ss.getIntValue("minicourse_id")
                clazz.unCollect(mid, ks.type, ks.id)
            }

提前造数据

这个就更常用了,有些时候我们在性能测试的时候,必须要进行前期大量测试数据的构造工作。关于这个话题,很多文章都写过了。我这里分享一下在多线程条件下,如何保证每个线程拿到参数唯一性的方法。

我先讲构造的数据通过配置文件(这里可以临时从数据库中查)读取到一个线程安全的LinkedBlockingQueue中,然后每个线程每次获取都取走一个对象,这样就可以满足需求了。

    static LinkedBlockingQueue<String> sqls = new LinkedBlockingQueue<>();

存储和获取的方法:

/**
     * 添加存储任务,数据库存储服务用
     *
     * @param sql
     * @return
     */
    public static boolean addWork(String sql) {
        try {
            sqls.put(sql);
        } catch (InterruptedException e) {
            logger.warn("添加数据库存储任务失败!", e);
            return false;
        }
        return true;
    }

    /**
     * 从任务池里面获取任务
     *
     * @return
     */
    static String getWork() {
        String sql = null;
        try {
            sql = sqls.poll(SqlConstant.MYSQLWORK_TIMEOUT, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            logger.warn("获取存储任务失败!", e);
        } finally {
            return sql;
        }
    }

这里需要提前预估消耗量,不然容易因为数据量准备不足导致测试失败。当然,也可以单独写一个线程,不断往队列中添加数据以保障测试用例顺利执行。

总结:

感谢每一个认真阅读我文章的人!!!

 我个人整理了我这几年软件测试生涯整理的一些技术资料,包含:电子书,简历模块,各种工作模板,面试宝典,自学项目等。欢迎大家点击下方名片免费领取,千万不要错过哦。

   Python自动化测试学习交流群:全套自动化测试面试简历学习资料获取点击链接加入群聊【python自动化测试交流】:http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DhOSZDNS-qzT5QKbFQMsfJ7DsrFfKpOF&authKey=eBt%2BF%2FBK81lVLcsLKaFqnvDAVA8IdNsGC7J0YV73w8V%2FJpdbby66r7vJ1rsPIifg&noverify=0&group_code=198408628

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

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

相关文章

机器人开发--EKF扩展卡尔曼滤波介绍

机器人开发--EKF卡尔曼滤波介绍 1 介绍1.1 概述KF (Kalman Filter)EKF (Extended Kalman Filter)UKF (Unscented Kalman Filter) 1.2 发展历史1.3 卡尔曼演化分支1.4 应用1.5 特点1.6 姿态估计问题 from 南叔先生1.7 EKF、PF、UKF 对比1.8 EKF 递归框架 2 理解機器人學&#xf…

使用Matplotlib画三维图

使用matplotlib画3D图&#xff1a; import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D# 创建X和Y的网格点 x np.linspace(-5, 5, 100) y np.linspace(-5, 5, 100) X, Y np.meshgrid(x, y)# 创建Z的网格点&#xff08;这里使用一…

nginx 配置m3u8播放视频

第一步nginx配置&#xff1a; 参考 csdn - CircleMouse Nginx配置搭建m3u8格式的视频播放服务 user www www; worker_processes auto; error_log /www/wwwlogs/nginx_error.log crit; pid /www/server/nginx/logs/nginx.pid; worker_rlimit_nofile 51200;stream {l…

提高情商的训练方法

在当今社会&#xff0c;情商已经成为了一个越来越受到重视的概念。情商指的是一个人在情感方面的智力水平&#xff0c;即情绪智商&#xff0c;包括了自我意识、自我管理、社交意识和关系管理等多个方面。而提高情商并非是天生的天赋&#xff0c;而是可以通过学习和实践获得的技…

自然语言处理从入门到应用——预训练模型总览:词嵌入的两大范式

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 相关文章&#xff1a; 预训练模型总览&#xff1a;从宏观视角了解预训练模型 预训练模型总览&#xff1a;词嵌入的两大范式 预训练模型总览&#xff1a;两大任务类型 预训练模型总览&#xff1a;预训练模型的拓展 …

【论文解读系列】MLLM研究综述

A Survey on Multimodal Large Language Models 1 中国科大科技学院、认知智能国家重点实验室 2 腾讯优图实验室 MLLM目录 0. 摘要1. 引言2. 总览3. 方法3.1 多模态指令调谐3.1.1 引言3.1.2 前言(Preliminaries)3.1.3 模态对齐3.1.4 数据3.1.5 模态桥接3.1.6 评估 3.2 多模态…

深入理解 Golang: 网络编程

Go 中的 Epoll 关于计算机网络分层与 TCP 通信过程过程此处不再赘述。 考虑到 TCP 通信过程中各种复杂操作&#xff0c;包括三次握手&#xff0c;四次挥手等&#xff0c;多数操作系统都提供了 Socket 作为 TCP 网络连接的抽象。Linux -> Internet domain socket -> SOC…

layui中文、以及图标乱码解决方案

最终解决方案…手动对js文件中的中文&#xff0c;用unicode进行编码

修改 ChatGLM2-6B 自我认知的 Lora 微调教程

修改 ChatGLM2-6B 自我认知的 Lora 微调教程 0. 背景1. 部署微调项目2. 数据集说明3. 模型监督微调(Lora)4. 模型效果测试5. 导出微调模型6. 调用导出的模型 0. 背景 现在开始学习微调&#xff0c;主要学习 Lora 微调。 这次尝试了修改 ChatGLM2-6B 自我认知&#xff0c;文章…

2023.7.2-【for语言】:输入一个整数,并输入该整数对应个数的整数,求他们的和与平均值

程序&#xff1a; int a;int b0;int c;int sum0;double ave;printf("请输入待求整数的个数&#xff1a;");scanf("%d",&a);for (b 1; b<a; b){printf("整数%d&#xff1a;", b);scanf("%d", &c);sum c;}printf("以上…

vite中的env环境变量

一、vite中使用env环境变量基本介绍 Vite 是一种现代化的前端构建工具&#xff0c;旨在提供快速的开发和构建体验。在 Vite 中&#xff0c;env 环境变量是一种用于在项目中设置和访问全局变量的机制。通过 env 变量&#xff0c;可以在不同环境下配置不同的参数&#xff0c;实现…

时间序列分解 | Matlab 互补集合经验模态分解(CEEMD)的信号分解

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列分解 | Matlab 互补集合经验模态分解(CEEMD)的信号分解 部分源码 %---------------------

Java基础---为什么不能用浮点数表示金额

目录 缘由 十进制转二进制 不是所有数都能用二进制表示 IEEE 754 避免精度丢失 缘由 因为不是所有的小数都能用二进制表示&#xff0c;所以&#xff0c;为了解决这个问题&#xff0c;IEEE提出了一种使用近似值表示小数的方式&#xff0c;并且引入了精度的概念这就是我们所…

Docker部署.Net7.0

1、新建项目 勾选启用Docker,会自动生成Dockerfile文件 2、生成镜像 打开PowerShell 进入项目解决方案目录路径 把项目打包成镜像 //镜像名称net7. 注意镜像名称后面的空格和点符号必须有docker build -t net7.0 .打包完成后可以看到项目的镜像 3、创建容器并启动 //…

C++文件操作 - 写操作----简单示例

C文件操作 - 写操作 一、什么是文件 内存中存放的数据在计算机关机后就会消失。要长久保存数据&#xff0c;就要使用硬盘、光盘、U盘等设备。为了便于数据的管理和检索&#xff0c;引入了“文件”的概念。 一篇文章、一段视频、一个可执行程序&#xff0c;都可以被保存为一个文…

BeanShell:多线程环境下Interpreter解释器的优化使用

BeanShell是用 Java 编写的一个小型、免费、可嵌入的 Java 代码的脚本解释器。 BeanShell动态执行标准Java语法&#xff0c;并使用通用语法对其进行扩展 脚本编写便利性&#xff0c;适用于 Java 的轻量级脚本。本文说明在并发环境下对BeanShell更加优化的使用方式。 简单示例 …

geoserver加载arcgis server瓦片地图显示异常问题处理

1.全能地图下载的瓦片conf.xml格式有问题首先要修改格式&#xff0c;conf.cdi文件也需要修改格式&#xff0c;修改为UTF-8或者UTF-8无BOM编码(不同的notepadd显示不同) 2. 下载的conf.xml坐标系默认从最小级别开始&#xff0c;一定要把前几级也补全&#xff0c;从0级开始 <L…

diffusion model

(正课)Diffusion Model 原理剖析 (1_4) (optional)_哔哩哔哩_bilibili(正课)Diffusion Model 原理剖析 (1_4) (optional)是【授权】李宏毅2023春机器学习课程的第42集视频&#xff0c;该合集共计64集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。http…

高中学习3大主流国际课程-申请国外大学本科

目录 作用 3大主流国际课程是什么 A-Level AP课程 IB 3大主流国际课程对比 作用 帮助学生申请国外大学本科。 如果能够选择到适合的国际课程&#xff0c;未来的留学规划就相当于成功了一半 3大主流国际课程是什么 A-Level、AP、IB三大国际课程 A-Level A-Level课程&a…

Kali Linux基础使用

Kali Linux基础使用 一、搭建渗透测试攻击环境1.1、Vmware workstation1.2、下载与安装1.3、安装渗透攻击机1.3.1、配置root用户登录1.3.2、普通用户切换到root用户1.3.3、修改kali语言1.3.4、网络配置1.3.4.1、桥接网络1.3.4.2、NAT1.3.4.3、仅主机 1.4、编辑网络文件 二、Lin…