手写java性能测试框架的实现示例

 更新时间:2022年07月21日 15:16:54   作者:FunTester  
这篇文章主要为大家介绍了java实现性能测试框架示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

之前写过一个性能测试框架,只是针对单一的HTTP接口的测试,对于业务接口和非HTTP接口还无非适配,刚好前端时间工作中用到了,就更新了自己的测试框架,这次不再以请求为基础,而是以方法为基础,这样就可以避免了单一性,有一个base类,然后其他的各种单一性请求在单独写一个适配类就好了,如果只是临时用,直接重新实现base即可。

代码分享

package com.fun.frame.thead;
import com.fun.frame.SourceCode;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import static com.fun.utils.Time.getTimeStamp;
/**
 * 多线程任务基类,可单独使用
 */
public abstract class ThreadBase<T> extends SourceCode implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ThreadBase.class);
    /**
     * 任务请求执行次数
     */
    public int times;
    /**
     * 计数锁
     * <p>
     * 会在concurrent类里面根据线程数自动设定
     * </p>
     */
    CountDownLatch countDownLatch;
    /**
     * 用于设置访问资源
     */
    public T t;
    public ThreadBase(T t) {
        this();
        this.t = t;
    }
    public ThreadBase() {
        super();
    }
    /**
     * groovy无法直接访问t,所以写了这个方法
     *
     * @return
     */
    public String getT() {
        return t.toString();
    }
    @Override
    public void run() {
        try {
            before();
            List<Long> t = new ArrayList<>();
            long ss = getTimeStamp();
            for (int i = 0; i < times; i++) {
                long s = getTimeStamp();
                doing();
                long e = getTimeStamp();
                t.add(e - s);
            }
            long ee = getTimeStamp();
            logger.info("执行次数:{},总耗时:{}", times, ee - ss);
            Concurrent.allTimes.addAll(t);
        } catch (Exception e) {
            logger.warn("执行任务失败!", e);
        } finally {
            after();
            if (countDownLatch != null)
                countDownLatch.countDown();
        }
    }
    /**
     * 运行待测方法的之前的准备
     */
    protected abstract void before();
    /**
     * 待测方法
     *
     * @throws Exception
     */
    protected abstract void doing() throws Exception;
    /**
     * 运行待测方法后的处理
     */
    protected abstract void after();
    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    public void setTimes(int times) {
        this.times = times;
    }
}

基础类实现

下面是几个实现过的基础类:

package com.fun.frame.thead;
import com.fun.httpclient.ClientManage;
import com.fun.httpclient.FanLibrary;
import com.fun.httpclient.GCThread;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
 * http请求多线程类
 */
public class RequestThread extends ThreadBase {
    static Logger logger = LoggerFactory.getLogger(RequestThread.class);
    /**
     * 请求
     */
    public HttpRequestBase request;
    /**
     * 单请求多线程多次任务构造方法
     *
     * @param request 被执行的请求
     * @param times   每个线程运行的次数
     */
    public RequestThread(HttpRequestBase request, int times) {
        this.request = request;
        this.times = times;
    }
    @Override
    public void before() {
        request.setConfig(FanLibrary.requestConfig);
        GCThread.starts();
    }
    @Override
    protected void doing() throws Exception {
        getResponse(request);
    }
    @Override
    protected void after() {
        GCThread.stop();
    }
    /**
     * 多次执行某个请求,但是不记录日志,记录方法用 loglong
     * <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>
     *
     * @param request 请求
     * @throws IOException
     */
    void getResponse(HttpRequestBase request) throws IOException {
        CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
        String content = FanLibrary.getContent(response);
        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
            logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());
        if (response != null) response.close();
    }
}

数据库的实现

package com.fun.frame.thead;
import com.fun.interfaces.IMySqlBasic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
/**
 * 数据库多线程类
 */
public class QuerySqlThread extends ThreadBase {
    private static Logger logger = LoggerFactory.getLogger(QuerySqlThread.class);
    String sql;
    IMySqlBasic base;
    public QuerySqlThread(IMySqlBasic base, String sql, int times) {
        this.times = times;
        this.sql = sql;
        this.base = base;
    }
    @Override
    public void before() {
        base.getConnection();
    }
    @Override
    protected void doing() throws SQLException {
        base.excuteQuerySql(sql);
    }
    @Override
    protected void after() {
        base.mySqlOver();
    }
}

concurrent类

package com.fun.frame.excute;
import com.fun.bean.PerformanceResultBean;
import com.fun.frame.Save;
import com.fun.frame.SourceCode;
import com.fun.frame.thead.ThreadBase;
import com.fun.profile.Constant;
import com.fun.utils.Time;
import com.fun.utils.WriteRead;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Concurrent {
    private static Logger logger = LoggerFactory.getLogger(Concurrent.class);
    /**
     * 线程任务
     */
    public ThreadBase thread;
    public List<ThreadBase> threads;
    public int num;
    public static Vector<Long> allTimes = new Vector<>();
    ExecutorService executorService;
    CountDownLatch countDownLatch;
    /**
     * @param thread 线程任务
     * @param num    线程数
     */
    public Concurrent(ThreadBase thread, int num) {
        this(num);
        this.thread = thread;
    }
    /**
     * @param threads 线程组
     */
    public Concurrent(List<ThreadBase> threads) {
        this(threads.size());
        this.threads = threads;
    }
    public Concurrent(int num) {
        this.num = num;
        executorService = Executors.newFixedThreadPool(num);
        countDownLatch = new CountDownLatch(num);
    }
    /**
     * 执行多线程任务
     */
    public PerformanceResultBean start() {
        long start = Time.getTimeStamp();
        for (int i = 0; i < num; i++) {
            ThreadBase thread = getThread(i);
            thread.setCountDownLatch(countDownLatch);
            executorService.execute(thread);
        }
        shutdownService(executorService, countDownLatch);
        long end = Time.getTimeStamp();
        logger.info("总计" + num + "个线程,共用时:" + Time.getTimeDiffer(start, end) + "秒!");
        return over();
    }
    private static void shutdownService(ExecutorService executorService, CountDownLatch countDownLatch) {
        try {
            countDownLatch.await();
            executorService.shutdown();
        } catch (InterruptedException e) {
            logger.warn("线程池关闭失败!", e);
        }
    }
    private PerformanceResultBean over() {
        Save.saveLongList(allTimes, num);
        return countQPS(num);
    }
    ThreadBase getThread(int i) {
        if (threads == null) return thread;
        return threads.get(i);
    }
    /**
     * 计算结果
     * <p>此结果仅供参考</p>
     *
     * @param name 线程数
     */
    public static PerformanceResultBean countQPS(int name) {
        List<String> strings = WriteRead.readTxtFileByLine(Constant.LONG_Path + name + Constant.FILE_TYPE_LOG);
        int size = strings.size();
        int sum = 0;
        for (int i = 0; i < size; i++) {
            int time = SourceCode.changeStringToInt(strings.get(i));
            sum += time;
        }
        double v = 1000.0 * size * name / sum;
        PerformanceResultBean performanceResultBean = new PerformanceResultBean(name, size, sum / size, v);
        performanceResultBean.print();
        return performanceResultBean;
    }
}

redis实现类缺失,因为没有遇到需要单独实现的需求。

关于用代码还是用工具实现并发,我个人看法所有所长,单究其根本,必然是代码胜于工具,原因如下:门槛高,适应性强;贴近开发,利于调优。

性能测试,并发只是开始,只有一个好的开始才能进行性能数据分析,性能参数调优。所以不必拘泥于到底使用哪个工具那种语言,据我经验来说:基本的测试需求都是能满足的,只是实现的代价不同。

groovy是一种基于JVM的动态语言,我觉得最大的优势有两点

  • 第一:于java兼容性非常好,大部分时候吧groovy的文件后缀改成java直接可以用,反之亦然。java的绝大部分库,groovy都是可以直接拿来就用的。这还带来了另外一个有点,学习成本低,非常低,直接上手没问题,可以慢慢学习groovy不同于Java的语法;
  • 第二:编译器支持变得更好,现在用的intellij的ide,总体来说已经比较好的支持groovy语言了,写起代码来也是比较顺滑了,各种基于groovy的框架工具也比较溜,特别是Gradle构建工具,比Maven爽很多。

以上就是java性能测试框架手写实现示例的详细内容,更多关于java 性能测试框架的资料请关注脚本之家其它相关文章!

相关文章

  • java提取json中某个数组的所有值方法

    java提取json中某个数组的所有值方法

    下面小编就为大家分享一篇java提取json中某个数组的所有值方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • Jpa中Specification的求和sum不生效原理分析

    Jpa中Specification的求和sum不生效原理分析

    这篇文章主要为大家介绍了Jpa中Specification的求和sum不生效原理示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 深度思考JDK8中日期类型该如何使用详解

    深度思考JDK8中日期类型该如何使用详解

    这篇文章主要介绍了JDK8中日期类型该如何使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Mybatis-Plus实现多主键批量保存及更新详情

    Mybatis-Plus实现多主键批量保存及更新详情

    这篇文章主要介绍了Mybatis-Plus实现多主键批量保存及更新详情,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • SpringBoot如何集成Netty

    SpringBoot如何集成Netty

    这篇文章主要介绍了SpringBoot如何集成Netty问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • java 获取路径的各种方法(总结)

    java 获取路径的各种方法(总结)

    下面小编就为大家带来一篇java 获取路径的各种方法(总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • Java Spring之@Async原理案例详解

    Java Spring之@Async原理案例详解

    这篇文章主要介绍了Java Spring之@Async原理案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • java递归法求字符串逆序

    java递归法求字符串逆序

    这篇文章主要介绍了java递归法求字符串逆序,涉及java递归调用的相关操作技巧,需要的朋友可以参考下
    2015-05-05
  • java读取xml配置参数代码实例

    java读取xml配置参数代码实例

    这篇文章主要介绍了java读取xml配置参数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 详解Spring如何扫描自定义的注解

    详解Spring如何扫描自定义的注解

    本文给大家详细介绍了Spring如何扫描自定义的注解,在Spring中,可以使用注解来实现依赖注入、AOP等功能,同时,Spring也支持自定义注解,使得开发人员可以更灵活地使用注解,需要的朋友可以参考下
    2024-02-02

最新评论