性能测试框架项目报告

项目报告:

心路历程:

项目的灵感来自一款叫做JMH的基准测试框架。
JMH是代码微基准测试的工具套件

什么是性能测试

系统在特定负载的情况下,相应时间和稳定性的表现情况。
1.系统:自己开发的程序,测试反映出我们开发程序的质量好坏。
2.负载:单位时间内客户请求的数量。
3.相应时间:客户从发起请求到接收到成功或失败响应的时间。
4.稳定性:指任意时间,响应时间的波动情况,波动越小的系统越好。

开发环境:

Windows环境下的IntelliJ IDEA

项目语言:

Java语言

项目功能:
  1. 自动加载测试用例
  2. 通过接口标记待测试类
  3. 通过注解标记待测试方法
  4. 通过注解实现多级配置
  5. 编译器预热
  6. 用POI生成Excel报表
项目技术

注解,反射,集合,接口,Java POI

项目详解:

首先来阐述一下性能测试框架的必要性,如果没有一个良好的性能框架,检测代码的性能就会不可避免的出现误差,举个栗子:
字符串拼接 vs StringBuilder拼接:

public class MainFirst {    
    private static String testStringAdd() {        
        String s = " ";        
        for (int i = 0; i < 10; i++) {            
            s += i;       
        }        
        return s;    
    }    
    private static String testStringBuildrtAdd() {        
        StringBuilder sb = new StringBuilder();        
        for (int i = 0; i < 10; i++) {            
            sb.append(i);        
        }        
        return sb.toString();    
    }    
    public static void main(String[] args) {        
        long t1 = System.nanoTime();        
        testStringAdd();        
        long t2 = System.nanoTime();        
        testStringBuildrtAdd();       
        long t3 = System.nanoTime();        
        System.out.printf("字符串相加:%d%n",t2-t1);        
        System.out.printf("StringBuilder:%d%n",t3-t2);    
    }
}

结果:
在这里插入图片描述
如果将执行顺序换一下:

 public static void main(String[] args) {        
        long t1 = System.nanoTime();        
        testStringBuildrtAdd(); 
        long t2 = System.nanoTime();        
        testStringAdd();     
        long t3 = System.nanoTime();        
        System.out.printf("字符串相加:%d%n",t3-t2);        
        System.out.printf("StringBuilder:%d%n",t2-t1);    
    }

结果:
在这里插入图片描述
看到这个结果时应该就能明白性能测试框架的重要性了。
猜测可能影响性能的因素:

  1. 执行时间过短
  2. 实验次数太少
  3. 编译器自动优化代码:AOT编译器,JIT编译器自动优化
  4. 没有预热

总结一下JMH大致是如何来建立框架的:
JMH:利用注解来完成配置:要测试的类和方法通过注解标注出来,每次的实验组次数通过注解配置,进行多少次试验也是通过注解配置。
所以重点是书写注解的过程,根据这些因素加上已经有的JMH框架,我们就可以自己写一个性能测试框架:

性能测试框架化:
  • 利用Benchmark注解标记出需要测试的方法
  • 利用Measurement注解配置测试的一些相关配置(3级配置:默认+类级别+方法级别)
  • 完成测试用例自动发现加载的过程
    1. 如何获取指定包下的所有类==>如何找到指定目录下的所有字节码文件
    2. 如何区分哪些类是需要测试的类(将要测试的类放在一个接口里)
  • 如何定义注解:注解的三个阶段(编译,编译-运行,运行):这里使用了运行阶段的注解的获取方式(利用反射)
1.注解的使用:

语法:
定义注解:

@interface Measurement {
    int iterations() default = 3;  //默认值
}

使用注解:
@Measurement(iterations = 10);如果没有默认值,就一定要给出值
或者:如果有默认值,则可以不给出值,有以下三种写法:
@Measurement 等同于@Measurement()等同于@Measurement(iterations = 3);
class Demo {

}

注解的分类:@RetentionPolicy:

  1. 在编译期间,文件变成*.class文件时,注解已经不存在了–SOURCE

  2. 在编译期间,文件变成*.class文件时,注解还存在,但是运行时不存在了–CLASS
    1和2是利用注解处理器:Annotations Processor来获取信息

  3. 运行期间,注解始终存在(保存在了方法区的类的元信息中)–RUNTIME
    3是利用Reflection(反射)来获取信息

注解的适用场景:(把代码逻辑转成配置逻辑
修改的代码逻辑的成本一定高于修改配置逻辑的成本
为什么直接用配置呢:因为有些配置和代码是强相关的

2.自动加载测试用例:

加载一个类 :如何找到这个类所在目录?

ClassLoader classLoader = Main.class.getClassLoader();
Enumeration<URL> urls = classLoader.getResources("包名");
while(urls.hasMoreElements()){
    URL url = urls.nextElement();
   // System.out.println(url.getPath());//目录有中文时会出现乱码
    //解决方法:System.out.println(URLDecoder.decode(url.getPath(), "UTF-8"));
   // System.out.println(url.getProtocal());
   //确定*.class
   File dir = new File(URLDecoder.decode(url.getPath(),"UTF-8"));
   if(!dir.isDirectory()){
        continue;
   }
   File[] files = dir.listFiles();
   if(files == null){
        continue;
   }
   for(File file : files){
   //严谨一点的话应该判断一下是不是java的字节码
        String filename = file.getName();
        Strign className = filename.substring(0,filename.length()-6);
        //System.out.println(className);
        //获取类的实例
        Class<?> cls = Class.forName("包名"+ className);
        //利用接口找出需要的class
        Class<?>[] interfaces = cls.getInterfaces();
        for(Class<?> interf :  interfaces){
                if(interf == Case.class){
                    System.out.println(className);
                }
        }
   }
}

找到类后,确定类中有哪些 “ * . class ”文件
这里只能处理“*.class”的情况,不能处理打成jar包的情况,jar包不在同一个目录下,需要另一个方法。
拿到类的名称后就可以获取类的实例,通过反射获取

3.用POI生成Excel报表
		//生成一个文档对象
       	HSSFWorkbook wb = new HSSFWorkbook();
        //在文档中生成一个表单对象
        HSSFSheet sheet = wb.createSheet("测试报表");
        //在表单里创建第一行
        HSSFRow row = sheet.createRow(0);
        //设施样式
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        //生成一个列对象
        HSSFCell cell = null;
        //给出表格的头名称
        String[] title = {"测试用例","测试次数","测试耗时"};
        for (int j = 0; j < title.length; j++) {
            //在第一行里创建列
            cell = row.createCell(j);
            //将元素填入第row行cell列里
            cell.setCellValue(title[j]);
            //设置样式
            cell.setCellStyle(style);
        }
        //输出一个Excel文件
        FileOutputStream outputStream = new FileOutputStream("E:/testBook.xls");
        try {
            //写入到文件中
            wb.write(outputStream);
            //关闭流
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

看一下报表结果:
在这里插入图片描述

4.系统预热

直接来看一下预热和不预热的结果比较,上面的图就是预热了的输出报表,下面给出没有预热的输出报表:
在这里插入图片描述
可以看到测试出来的差别,所以预热还是很有必要的。
预热代码:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//系统预热
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WarmUp {
    int iterations() default 2000;
}

在执行测试用例之前进行预热:

//进行预热
        int warm=1000 ;
        WarmUp warmup=method.getAnnotation(WarmUp.class);
        if(warmup!=null){
            warm=warmup.iterations();
        }
        for(int w=0;w<warm;w++){
            method.invoke(bCase);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值