一、性能测试的概念

性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试。负载测试和压力测试都属于性能测试,两者可以结合进行。

通过负载测试,确定在各种工作负载下系统的性能,目标是当负载逐渐增加时,测试系统各项性能指标的变化情况。压力测试时通过确定一个系统的瓶颈或者不能接受的性能点,来获取系统能提供的最大服务级别的测试。性能测试主要包括负载测试、强度测试、容量测试。

二、性能测试的指标

web服务器:

Avg Rps: 平均每秒的响应次数 = 总请求数 /秒数;

Avg time to last byte per terstion(mstes): 平均每秒业务脚本的迭代次数;

Successful Rounds: 成功的请求;

Failed Rounds: 失败的请求;

Successful Hits: 成功的点击次数;

Failed Hits: 失败的点击次数;

Hits Per Second: 每秒点击次数;

Successful Hits Per Second:每秒成功的点击次数;

Failed Hits Per Second: 每秒失败的点击次数;

Attempted Connections: 尝试连接数;

Throughput: 吞吐率;

数据库服务器:

User Connections: 用户连接数,也就是数据库的连接数量;

Number of Deadlocks: 数据库死锁;

Butter Cache Hit: 数据库Cache 的命中情况;

三、性能测试的流程

1.明确性能测试需求;

2.制定性能测试方案;

2.1.测试范围

2.2.入口标准

2.3.出口标准

2.4.测试策略(测试环境指标、存量数据、业务场景、测试通过标准等)

2.5.测试风险

2.6.测试资源

3.设计性能测试用例;

4.执行性能测试用例;

5.分析性能测试结果;

6.生成性能测试报告;

四、性能测试的工具--JMeter

        为什么是JMeter而不是LoadRunner呢  1.更少的投入,针对有限的测试成本;  2.开源工具的可定制性无可比拟;  3.通过社区得到最大程度的支持。

JMeter是Apache组织开发的基于Java的压力测试工具。最初被设计用于web应用的测试,后来扩展到其他测试领域。可用于测试静态和动态资源,如文件、Java服务

程序、Java对象、数据库等。JMeter能够对应用程序做功能/回归测试,通过创建带有断言的脚本来验证被测程序返回了期望的结果。而且为了保证最大限度的灵活性,

JMeter允许使用正则表达式创建断言。

五、JMeter的特性

1.支持对多种服务类型进行测试;

2.支持通过录制/回访方式获取测试脚本;

3.具备高可移植性,是纯Java 程序;

4.采用多线程框架,允许通过多个线程并发取样及通过独立的线程组对不同的功能同时取样;

5.精心设计的GUI支持高速用户操作和精确计时;

6.支持缓存和离线的方式分析/回放测试结果;

7.高扩展性;

六、JMeter常用测试元件

1.线程组

用来管理执行性能测试所需的JMeter线程。

a.可以设置线程数量

b.设置线程启动周期

c.设置执行测试脚本的循环次数

2.控制器

JMeter有两种类型的控制器:采样器和逻辑控制器。

采样器被用来向服务器发送请求。JMeter采样器包含:FTP Request、HTTP Request、JDBC Request等。

逻辑控制器用来控制JMeter的测试逻辑,特别是何时发送请求。

3.监听器

监听器提供了对JMeter在测试期间收集到的信息的访问方法。

4.定时器

JMeter线程在发送请求之间没有间歇,通过添加定时器,设定请求之间应该间隔的时间。

5.断言

可以使用断言来检查从服务器获得的响应内容。

6.配置元件

配置元件与采样器紧密关联。虽然配置元件并不发送请求,但可添加或修改请求。

7.前置处理器

会在采样器发出请求之前做一些操作。

8.后置处理器

会在采样器发出请求之后做一些操作。

JMeter执行顺序:配置元件=》前置处理器=》定时器=》采样器=》后置处理器=》断言=》监听器

七、辅助测试工具开发

下面的代码(工具:sqlexec)是一个用来向数据库(目前支持Oracle、Mysql)插入测试数据的工具。支持多线程,可插入千万级别测试数据。在后续压测中会用到该

工具,工具开发尽量简单,一个工具只完成一个任务,同时不要重复制造轮子。

[java] view plaincopy

  1. package d706;
  2. /*
  3. * sql处理
  4. */
  5. public class Test_DB_Insert extends Thread{
  6. public static String SQLTEXT = null;  // 待处理的sql语句
  7. private InputStream ins = null;       // 用于读取配置文件
  8. private Properties property = new Properties(); // 读取数据库配置文件
  9. private String databaseType = null; // 数据库连接类型
  10. private String driver = null;       // 数据库驱动
  11. private String url = null;          // 数据库连接
  12. private String uName = null;        // 数据库登录用户名
  13. private String pwd = null;          // 数据库登录用户密码
  14. private  int numOfTestRecords;      // 插入数据条数
  15. private  Connection con = null;     // 连接数据库
  16. private  PreparedStatement statement = null;  // 获取数据库操作对象
  17. public  Test_DB_Insert(String sql){
  18. SQLTEXT = sql;                  // sql语句以参数的形式,在构造实例的时候传入
  19. }
  20. private void init(){   // 初始化配置文件
  21. try{
  22. ins = new FileInputStream("./d706/dbconf.properties");
  23. }catch(FileNotFoundException ffe){
  24. ffe.printStackTrace();
  25. }
  26. try{
  27. property.load(ins);   //
  28. }catch(IOException ie){
  29. ie.printStackTrace();
  30. }
  31. databaseType = property.getProperty("databasetype"); // 获取配置文件中设置的连接数据库类型
  32. if(databaseType.toUpperCase().equals("MYSQL")){      // 判断连接数据库类型
  33. driver = property.getProperty("driver_mysql");
  34. url = property.getProperty("url_mysql");
  35. uName = property.getProperty("db_userName_mysql"); // 连接数据库的用户信息;
  36. pwd = property.getProperty("db_pwd_mysql");
  37. }else if(databaseType.toLowerCase().equals("oracle")){ //
  38. driver = property.getProperty("driver_oracle");
  39. url = property.getProperty("url_oracle");
  40. uName = property.getProperty("db_userName_oracle");
  41. pwd = property.getProperty("db_pwd_oracle");
  42. }
  43. }
  44. private  synchronized  void Insert_DB(){
  45. try {
  46. try {
  47. Class.forName( driver );  // 注册驱动;
  48. }catch(ClassNotFoundException cf){
  49. cf.printStackTrace();
  50. }
  51. con = DriverManager.getConnection(url,uName, pwd); // 获取数据库连接
  52. con.setAutoCommit(false);  // 关闭事务自动提交
  53. SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:SS");  // 记录执行时间
  54. TimeZone t = sdf.getTimeZone();
  55. t.setRawOffset(0);
  56. sdf.setTimeZone(t);
  57. Long startTime = System.currentTimeMillis();
  58. System.out.println("插入数据操作开始...");
  59. statement = con.prepareStatement(SQLTEXT); //创建数据库操作对象
  60. /*
  61. * "INSERT INTO TEST_DB(name,sex,nickname,test1,test2,test3,test4," +
  62. "test5,test6,test7,test8,test9,test10,test11,test12,test13,test14," +
  63. "test15,test16,test17,test18,test19,test20,test21,test22,test23," +
  64. "test24,test25,test26,test27,test28,test29,test30,test31,test32," +
  65. "test33,test34,test35,test36,test37,test38,test39,test40,test41," +
  66. "test42) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," +
  67. "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
  68. */
  69. numOfTestRecords = 1000;                               //插入的测试数据量;
  70. for(int i = 0; i<numOfTestRecords; i++) {              //循环
  71. statement.setString(i + 1, "DBTest-" + i);
  72. //statement.setString(2, "" + i%2);          //0表示男 1表示女
  73. statement.addBatch();  // 把一个SQL命令加入命令列表
  74. //statement.executeUpdate(); //执行SQL;
  75. }
  76. statement.executeBatch(); //执行批量更新
  77. con.commit();//语句执行完毕,提交事务
  78. //int[] ref = statement.executeBatch();
  79. //if(ref[numOfTestRecords-1] == 0){System.out.println("插入数据操作完成");} //
  80. System.out.println("插入数据操作完成");
  81. Long endTime = System.currentTimeMillis();
  82. System.out.println("插入"+numOfTestRecords+"条数据,"+"用时(时:分:秒:毫秒)" +
  83. sdf.format(new Date(endTime - startTime))); //
  84. }catch(Exception e) {
  85. System.out.println("异常: " + e.toString());
  86. e.printStackTrace();
  87. }finally{
  88. if(statement != null){   // 关闭数据库操作对象
  89. try{
  90. statement.close();
  91. }catch(SQLException se){
  92. se.printStackTrace();
  93. }
  94. }
  95. if(con != null){         // 关闭数据库连接
  96. try{
  97. if(con.isClosed()){con.close();}
  98. }catch(SQLException se){
  99. se.printStackTrace();
  100. }
  101. }
  102. }
  103. }
  104. @Override
  105. public void run() {    // 类外调用
  106. Test_DB_Insert ti = new Test_DB_Insert(SQLTEXT); // 构造实例
  107. ti.init();      // 初始化
  108. ti.Insert_DB(); // 执行插入数据
  109. }
  110. //  public static void main(String[] args){
  111. //
  112. //          Test_DB_Insert ti = new Test_DB_Insert(SQLTEXT);
  113. //          ti.init();  //初始化
  114. //          ti.Insert_DB();  //执行插入数据
  115. //  }
  116. }

// 针对增删查改,可放到一个SQL处理类(Test_DB_crud)中,判断传入的SQL字符串,然后交给对应的方法去执行并在控制台输出结果。 在Test_DB_Control类

中只是new一个Test_DB_crud类,形成了Test_DB_crud对Test_DB_Control的依赖关系。

[java] view plaincopy

  1. package d706;
  2. /*
  3. *程序界面
  4. *按钮事件
  5. */
  6. public class Test_DB_gui extends JFrame implements ActionListener{
  7. private static final long serialVersionUID = 1L;
  8. public static String SQLTEXT = null; // 界面输入的sql文本
  9. private JScrollPane js = null;
  10. private JPanel jp1 = null;
  11. private JTextArea ta = null;
  12. private JButton jb = new JButton();
  13. public Test_DB_gui(){
  14. this.setTitle("sqlExecV1.0");
  15. ta = new JTextArea();
  16. ta.setText("");
  17. js = new JScrollPane(ta);
  18. jp1 = new JPanel();
  19. jp1.setLayout(new BorderLayout());
  20. jp1.add(js,BorderLayout.CENTER);
  21. jb = new JButton();
  22. jb.setText("执行");
  23. jb.addActionListener(this); // 添加监听
  24. jp1.add(jb,BorderLayout.SOUTH);
  25. this.getContentPane().add(jp1);
  26. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  27. this.setBounds(400,200,700,500);
  28. this.setVisible(true);
  29. jb.addActionListener(new ActionListener(){  // 按钮事件
  30. public void  actionPerformed(ActionEvent e) {  // 匿名内部类的形式实现按钮事件
  31. SQLTEXT = ta.getText(); // 将要执行的SQL设置成静态的
  32. Multi_process mp = new Multi_process(SQLTEXT); // 在构造实例时,传入sql
  33. mp.run(); // 运行程序
  34. //System.out.println( mp.SQLTEXT +"***"); // 控制台输出
  35. }
  36. });
  37. }
  38. public void  actionPerformed(ActionEvent e) {
  39. // 实现 ActionListener 接口,需要实现的方法
  40. }
  41. public void run() {  // 运行方法
  42. Test_DB_gui np =  new Test_DB_gui();
  43. System.out.println( np.getTitle() );
  44. }
  45. }

[java] view plaincopy

  1. public class Multi_process {
  2. /*
  3. *多线程
  4. */
  5. public static String SQLTEXT = null;  // 待处理的sql语句
  6. public Multi_process(String sql){
  7. SQLTEXT = sql;                    // sql语句以参数的形式,在构造实例的时候传入
  8. }
  9. public  void run(){
  10. Test_DB_Insert  td1 = new Test_DB_Insert(SQLTEXT); // 创建实例
  11. //     Test_DB_Insert  td2 = new Test_DB_Insert(SQLTEXT);
  12. Thread t1 = td1;  // 创建线程
  13. //         Thread t2 = td2;
  14. t1.start(); // 启动线程
  15. //         t2.start();
  16. //     Test_DB_Insert t3 = new Test_DB_Insert();
  17. //     Test_DB_Insert t4 = new Test_DB_Insert();
  18. //     t3.run();
  19. //     t4.run();
  20. }
  21. }

[java] view plaincopy

  1. public class Test_Exec {
  2. /*
  3. * 程序入口
  4. */
  5. public static void main(String[] args){
  6. Test_DB_gui np = new Test_DB_gui();
  7. np.run();
  8. }
  9. }

在Linux下执行,需打成jar包,通过shell脚本执行。以下是sqlexec的startup.sh执行脚本.

[plain] view plaincopy

  1. #!/bin/sh
  2. #
  3. #Author: bruce
  4. #Version: sqlExecv1.0
  5. #Date:2013-11-20
  6. #
  7. read -p "please input jar file path:" jarpath
  8. java -jar "$jarpath"
  9. echo "running sqlExec."

注:

今天突然想到测试数据的一个问题。即造出来的数据应该更接近真实,而不是都一样。所以想利用配置文件的方式,在配置文件中写好SQL,程序读取执行配置文件

并动态生成SQL,完成插入测试数据。这样就解决了测试数据不够真实,可能影响测试结果的问题。---------2014年11月27日

【转】学习使用Jmeter做压力测试(一)--压力测试基本概念的更多相关文章

  1. 学习使用Jmeter做压力测试(一)--压力测试基本概念

    学习使用Jmeter做压力测试(一)--压力测试基本概念 一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测 ...

  2. 学习总结——JMeter做http接口功能测试

    JMeter对各种类型接口的测试 默认做接口测试前,已经给出明确的接口文档(如,http://test.nnzhp.cn/wiki/index.php?doc-view-59):本地配好了JMeter ...

  3. (转)学习使用Jmeter做压力测试(一)--压力测试基本概念

    一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测试,两者可以结合进行. 通过负载测试,确定在各种工作负载下 ...

  4. 学习总结——JMeter做http接口压力测试

    JMeter做http接口压力测试 测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做 ...

  5. (转)学习使用Jmeter做压力测试(三)--数据库测试

    数据库测试 JMeter可以做为Web服务器与浏览器之间的代理网关,以捕获浏览器的请求和Web服务器的响应,这样就可很容易的生成性能测试脚本. 根据脚本,JMeter可通过线程组来模拟真实用户对Web ...

  6. 【转】学习使用Jmeter做压力测试(三)--数据库测试

    JMeter可以做为Web服务器与浏览器之间的代理网关,以捕获浏览器的请求和Web服务器的响应,这样就可很容易的生成性能测试脚本.根据脚本,JMeter可通过线程组来模拟真实用户对Web服务器做压力测 ...

  7. 【转】学习使用Jmeter做压力测试(二)--压力测试的实施

    JMeter测试步骤: 1.建立测试计划 2.添加线程组 3.添加HTTP请求 4.增加监听器 5.执行测试计划 6.根据JMeter提供的报告分析结果 一.目标 测试访问目标服务器网站首页的每秒查询 ...

  8. 学习使用Jmeter做压力測试(一)--压力測试基本概念

    一.性能測试的概念         性能測试是通过自己主动化的測试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行測试.负载測试和压力測试都属于性能測试,两者能够结合进行. 通过负载測试, ...

  9. 学习总结——JMeter做WebService接口功能测试

    用JMeter作WebService接口功能测试(可以借助SoapUI来完成) SoapUI里面的操作: Wsdl文件或链接导入或添加到SoapUI打开待测请求:运行请求:取URL  SOAPActi ...

随机推荐

  1. C语言中单引号和双引号

    写惯了python对单引号和双引号都混了.. C语言中的单引号和双引号含义迥异,用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值,因此,采用ASCII字符集的 ...

  2. 漂亮的Html5网站

    http://www.mrdoob.com/projects/chromeexperiments/ball-pool/

  3. Codeforces Round #394 (Div. 2) A. Dasha and Stairs

    A. Dasha and Stairs time limit per test:2 seconds memory limit per test:256 megabytes input:standard ...

  4. fastclick插件 导致 日期插件无法触发

    fastclick源文件中有这一行,加个if条件就可以了 当touchend的时候我们判断一下他的event.target到底是啥,如果是date我们就不玩了,不要你fastclick了,用原生的去触 ...

  5. C++轮子队 敏捷冲刺

    团队Github地址:https://github.com/Pryriat/2048.git 敏捷开发——第1天 Alpha阶段第1次Scrum Meeting 敏捷开发起始时间 2018/10/27 ...

  6. CSS样式:覆盖规则

    规则一:由于继承而发生样式冲突时,最近祖先获胜. CSS的继承机制使得元素可以从包含它的祖先元素中继承样式,考虑下面这种情况: <html> <head> <title& ...

  7. Arcgis for JS扩展GraphicLayer实现区域对象的聚类统计与展示

    功能需求: 分省市统计并展示全国雨量站的数目与位置. 常规做法: 分省市雨量站的数目通过统计表的形式在页面端展示,位置根据XY坐标信息将雨量站标绘在图上. 优化做法: 去掉统计图的展示方式,直接将各省 ...

  8. Comparing Xamarin and Delphi XE5 to Xcode for Cross Platform Mobile App Development

    Comparing Xamarin and Delphi XE5 to Xcode for Cross Platform Mobile App Development If you are consi ...

  9. 2017年终巨献阿里、腾讯最新Java程序员面试题,准备好进BAT了吗

    Java基础 进程和线程的区别: Java的并发.多线程.线程模型: 什么是线程池,如何使用? 数据一致性如何保证:Synchronized关键字,类锁,方法锁,重入锁: Java中实现多态的机制是什 ...

  10. C++ 资源管理 —— RAII

    RAII:在构造函数中申请资源,在析构函数中释放资源. 1. RAII 自动实现锁资源的释放 void bad() { m.lock(); f(); if (COND) return; m.unloc ...