• nGrinder介绍、编写脚本与执行(完整版)


    https://blog.csdn.net/m0_46570759/article/details/124703537

    目录:

    • 性能测试工具的选型

    • nGrinder的介绍

    • nGrinder环境的搭建

    • Groovy语言的介绍

    • 常用的工具类

    • nGrinder代码实例

    • 执行测试

    一、性能测试工具的选型

    1、主流的性能测试工具 LoadRunner JMeter 与 nGrinder对比

    1.1、Loadrunner

    • 基于UI操作,容易上手。早期很流行,功能强大,但是太笨重,安装很麻烦。
    • 不开源,扩展性不高,收费贵。往后的方向肯定是客户端工具逐步向平台化发展,所以已经慢慢被替代了。

    1.2、JMeter

    • 基于UI操作,容易上手,但是编程能力较弱(使用beanshell脚本语言)。
    • 其次JMeter基于线程(单进程,多线程,循环N次),单节点模拟数千用户几乎不可能。支持平台化集成,也诞生了一些开源平台,如MeterSphere

    1.3、nGrinder

    • 单节点可支持5000+并发(多进程,多线程)、支持分布式、可监控被测服务器、可录制脚本、开源、平台化
    • 易于二次开发
    • 参数化功能较弱
    • 对测试人员的代码要求较高

    比较点

    JMeter

    Ngrinder

    LoadRunner

    实现语言 Java java/python java/VB/C/.NET
    使用方式 C/S或Command B/S C/S
    支持分布式 master/slave  controller/agent master/slave
    开源方式 免费,完全开源 免费,完全开源 收费
    支持协议 多种协议 多种协议 多种协议
    资源监控 monitor/plugin,如果二开,需要查找plugin的源码 monitor方式 自带资源监控功能
    社区活跃度 文档完善 有中文社区 网上资料和相关培训很多,购买正版还可以得到技术支持
    是否需要编码 基本不需要 需要,Jython/Groovy 需要
    脚本的维护 本地 内置SVN,可以修改成git 本地
    脚本录制 可使用BadBoy进行录制 可通过PTS插件进行录制 自带录制功能
    可扩展性 可增加plugin,输出结果可以再加工,扩展性强 可增加plugin,扩展性强 通过扩展函数库实现
    安装 简单,解压即可 简单,可以下载安装包或绿色包解压 安装包比较大,安装繁琐
    平台化 有开源或云端的压测平台 本身具备

    官网给出的最大虚拟用户数

    二、nGrinder的介绍

    1、背景

    官网地址

        nGrinder是韩国一家公司居于Grinder二次开发的一个性能平台。nGrinder具有 开源、易用、高可用、高扩展等特性,在Grinder基础上实现了多测试并行,通过web管理,实现了集群,同时支持Groovy和Jython脚本语言,(官方上说Groovy的性能会更好),也实现了对目标服务的监控以及插件的扩展,实现更多用户虚拟用户并发(官方上说,8G内存的4核cpu机器可以支持高到8000个虚拟用户),在同一线程中,不断重复的执行测试脚本,来模拟很多并发用户

    2、nGrinder 由三个主要的组件组成

    Controller
       1. 分发调度测试任务
       2.协调测试进程
       3. 整理和显示测试的统计结果
       4. 用户创建和修改脚本
    Monitor
        1.用于监控被测服务器的系统性能(例如:CPU/MEMORY)
        2.必须部署在被测服务器上
    Agent
        1.压测任务的拉取
        2.在代理服务器上加载运行测试进程和线程
        3. 监控施压机器的系统性能(例如:CPU/MEMORY/网卡/磁盘)

    3、工作原理

    基于官方文档翻译

    3.1、非集群架构图

     nGrinder 是一款在一系列机器上执行 Groovy 或 Jython 测试脚本的应用,内部引擎是基于 Grinder。 nGrinder 使用 controller 和 agent 分别包装了 Grinder 的 console 和 agent ,而且扩展了多种功能使其能够支持并发测试。

     nGrinder 在 Grinder 的基础上:

    • 实现多测试并行
    • 基于web的管理
    • 实现cluster
    • 内置svn,方便的脚本编辑、管理
    • 支持Groovy脚本,相对于Jython,可以启动更多的虚拟用户
    • 实现对目标服务器的监控
    • 插件系统扩展

    3.2、集群架构
    nGrinder 从 3.1 版本开始支持 controller集群

    归纳

    • 由一个控制端controller和多个代理端agent组成,通过控制端(浏览器访问)建立测试场景,然后分发到代理端进行压力测试。
    • 用户按照一定规范编写测试脚本,controller会将脚本以及需要的资源分发到agent,用jython、groovy执行。
    • 在脚本执行的过程中收集运行情况、相应时间、测试目标服务器的运行情况等。并且保存这些数据生成测试报告,通过动态图和数据表的形式展示出来。用户可以方便的看到TPS、被测服务器的CPU和内存等情况。

    三、nGrinder环境的搭建

    以linux 这里采用的版本是centos 6 64bit,性能测试工具不建议在Windows上部署。

    下载nGrinder

    选择最新的war包。

    服务器端启动: # nohup java -XX:MaxPermSize-256m -jar ngrinder-controller-3.5.2.war --port 8080 >output 2>&1 &

    这样nGrinder的管理页面就部署好,你可以简单的把ngrinder-controller的功能理解为性能测试展示和控制,后面会进行详细介绍。

    打开网址:

    http://xxx.xxx.xxx.xxx:8080/login

    默认用户名和密码都为admin

    下载和agent 

    下载agent   tar包(进入主页,点击 admin →Download Agent),然后进行解压  tar  -xvf  ngrinder-agent-3.5.2.tar

    解压agent 后,目录结构如下,编辑进入__agent.conf 

    如果controller和agent在同一台机器,则修改 agent.controller_host=127.0.0.1

    启动agent:   [ops@qa.test.jmeter-00.hz ngrinder-agent]$ nohup ./run_agent.sh >output 2>&1 &


    四、Groovy语言的简介

    1.什么是groovy?

           Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。

           Groovy是一种基于Java平台的面向对象语言。 Groovy 1.0于2007年1月2日发布,其中Groovy 2.4是当前的主要版本。 Groovy通过Apache License v 2.0发布。

          目前最新版本为2.5.3。

    2.Groovy的特点

    Groovy中有以下特点:

    • 同时支持静态和动态类型
    • 支持运算符重载
    • 本地语法列表和关联数组
    • 对正则表达式的本地支持
    • 各种标记语言,如XML和HTML原生支持
    • Groovy对于Java开发人员来说很简单,因为Java和Groovy的语法非常相似
    • 您可以使用现有的Java库
    • Groovy扩展了java.lang.Object

    动态类型

    类型对于变量,属性,方法,闭包的参数以及方法的返回类型都是可有可无的,都是在给变量赋值的时候才决定它的类型, 不同的类型会在后面用到,任何类型都可以被使用,即使是基本类型 (通过自动包装(autoboxing)). 当需要时,很多类型之间的转换都会自动发生,比如在这些类型之间的转换: 字符串(String),基本类型(如int) 和类型的包装类 (如Integer)之间,可以把不同的基本类型添加到同一数组(collections)中。

    运算符重载

    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

    3.类

    Groovy类和java类一样,完全可以用标准java bean的语法定义一个Groovy类。但作为另一种语言,可以使用更Groovy的方式定义类,这样的好处是,可以少写一半以上的javabean代码。

    (1)不需public修饰符

    如前面所言,Groovy的默认访问修饰符就是public,如果Groovy类成员需要public修饰,则根本不用写它。

    (2)不需要类型说明

    同样前面也说过,Groovy也不关心变量和方法参数的具体类型。

    (3)不需要getter/setter方法

    在很多ide(如eclipse)早就可以为程序员自动产生getter/setter方法了,在Groovy中,不需要getter/setter方法--所有类成员(如果是默认的public)根本不用通过getter/setter方法引用它们(当然,如果一定要通过getter/setter方法访问成员属性,Groovy也提供了它们)。

    (4)不需要构造函数

    不再需要程序员声明任何构造函数,因为实际上只需要两个构造函数(1个不带参数的默认构造函数,1个只带一个map参数的构造函数--由于是map类型,通过这个参数可以构造对象时任意初始化它的成员变量)。

    (5)不需要;结尾

    Groovy中每一行代码不需要分号作为结束符。

    五、常用的工具类

    1、生成随机字符串(import org.apache.commons.lang.RandomStringUtils)

    1.  
      数字:RandomStringUtils.randomNumeric(length);
    2.  
      字母:RandomStringUtils.randomAlphabetic(length);
    3.  
      字母加数字:RandomStringUtils.randomAlphanumeric(length);
    4.  
      所有ASCCII字符:RandomStringUtils.randomAscii(length);
    5.  
      自定义混合字符:RandomStringUtils.randomAscii(length, string);

    2、生成随机数字:(import java.util.concurrent.ThreadLocalRandom;)

        数字:int random_number = ThreadLocalRandom.current().nextInt(min_num, max_num);
    

    3、获取项目数据文件路径

    1.  
      common项目:"/resources/account.txt"
    2.  
      maven项目:Thread.currentThread().getContextClassLoader().getResource("/account.txt").getPath();
    3.  
      maven项目获取文件内容:ReflectionUtils.getCallingClass(0).getResourceAsStream("/account.txt").getText("UTF-8")

    4、读取文件:

    1.  
      txt每行单数据: String[] file_arrary = new File("/resources/account.txt") as String[];
    2.  
      String file_data = file_arrary[arrary_index];
    3.  
       
    4.  
      txt每行双数据: String[] file_arrary = new File("/resources/account.txt") as String[];
    5.  
      String data_one = file_arrary[arrary_index].split(",")[0];
    6.  
      String data_two = file_arrary[arrary_index].split(",")[1];
    7.  
      另一种方法:
    8.  
      List<String> reqDataArrList = new File(dataFilePath).readLines()
    9.  
      String data_one = reqDataArrList.get(arrary_index).split(",")[0];
    10.  
      String data_two = reqDataArrList.get(arrary_index).split(",")[1];
    11.  
       
    12.  
      txt每行多数据可参考双数据方法。也可以参考json方式存储:
    13.  
      BufferedReader txt_content=new BufferedReader(new FileReader(new File("/resources/account.txt")))
    14.  
      data_json = new JSONObject()
    15.  
      String text_line = ""
    16.  
      while(( text_line=txt_content.readLine())!=null){
    17.  
      data_json.put(text_line.split(",")[0],text_line.split(",")[1])
    18.  
      }
    19.  
      String data_one = data_json.keys[0]
    20.  
      String data_two = data_json.getString(data_one)

    5、写入文件:

    1.  
      覆盖写入: def write = new File(file_path, file_name).newPrintWriter();
    2.  
      write.write(write_text);
    3.  
      write.flush();
    4.  
      write.close()
    5.  
       
    6.  
      追加写入: def write = new File(file_path, file_name).newPrintWriter();
    7.  
      write.append(write_text);
    8.  
      write.flush();
    9.  
      write.close()

    6、json文件的数据处理(import org.ngrinder.recorder.RecorderUtils)

    1.  
      json文件读取: String json_str = new File(file_path).getText("UTF-8")
    2.  
      def json_object = RecorderUtils.parseRequestToJson(json_str)
    3.  
       
    4.  
      长度:json_object.length()
    5.  
      关键字:json_object.keys()
    6.  
      添加元素:json_object.put(name, value)
    7.  
      修改元素:json_object.put(name, value)
    8.  
      删除元素:json_object.remove(name, value)
    9.  
      获取对应value:json_object.getString(name)

    7、字符串的处理

    1.  
      字符串截取:String new_str = old_str[0..3]
    2.  
      字符串替换:String string = str.replace("old","new")
    3.  
      字符串统计:int count = string.count("char")
    4.  
      字符串转化:int int_num = Integer.parseInt(string)

    1、设置多个请求事务(即多个test方法)

    1.  
      1)设置多个静态Gtest对象:
    2.  
      public static GTest test1
    3.  
      public static GTest test2
    4.  
      2)实例化多个Gtest对象:
    5.  
      test1 = new GTest(1, "test1");
    6.  
      test2 = new GTest(2, "test2");
    7.  
      3)监听多个test请求:
    8.  
      test1.record(this, "test1")
    9.  
      test2.record(this, "test2")
    10.  
      4)定义多个test方法:
    11.  
      public void test1(){
    12.  
      grinder.logger.info("---ones: {}---", grinder.threadNumber+1)
    13.  
      }
    14.  
      public void test2(){
    15.  
      grinder.logger.info("---twos: {}---", grinder.threadNumber+1)
    16.  
      }

    2、Ngrinder定义请求参数集:

    1.  
      add方法: List<NVPair> paramList = new ArrayList<NVPair>();
    2.  
      paramList.add(new NVPair("name", "value"));
    3.  
      paramList.add(new NVPair("name", "value"));
    4.  
      params = paramList.toArray();
    5.  
       
    6.  
      new方法: params = [new NVPair("name", "value"), new NVPair("name", "value")];

    3、Ngrinder处理日志:

    1.  
      日志级别(三种常见): grinder.logger.info("----before process.----");
    2.  
      grinder.logger.warn("----before process.----");
    3.  
      grinder.logger.error("----before process.----");
    4.  
       
    5.  
      日志限定(仅打印error级别) :
    6.  
      1)导入依赖包
    7.  
      import ch.qos.logback.classic.Level;
    8.  
      import org.slf4j.LoggerFactory;
    9.  
      2)设定级别
    10.  
      @BeforeThread
    11.  
      LoggerFactory.getLogger("worker").setLevel(Level.ERROR);
    12.  
      3)设置打印语句
    13.  
      @test
    14.  
      grinder.logger.error("----error.----");
    15.  
      日志输出(输出所有进程日志):将每个agent的.ngrinder_agent/agent.conf中一项修改为agent.all_logs=true
    16.  
       
    17.  
      日志打印:打印变量:grinder.logger.error("{},{}",variable1,variable2); // 换行或缩进可在""中加\n或\t

    4、Ngrinder的cookie处理

    1.  
      1) 登录产生cookie
    2.  
      @BeforeThread
    3.  
      login_get_cookie(); // 调用登录方法
    4.  
      cookies = CookieModule.listAllCookies(HTTPPluginControl.getThreadHTTPClientContext()); // 配置cookie管理器
    5.  
      2) 读取控制器中cookie
    6.  
      @Before
    7.  
      cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }

    5、Ngrinder请求方式:

    1.  
      1)通过url加参数直接访问:
    2.  
      post方法: HTTPResponse result = request.POST("http://192.168.2.135:8080/blogs", params, headers)
    3.  
      get方法: HTTPResponse result = request.GET("http://192.168.2.135:8080/blogs", params, headers)
    4.  
      参数是json:设置请求头参数{"Content-Type": "application/json"}
    5.  
      2)通过参数化所有请求数据为json对象(导入import org.ngrinder.recorder.RecorderUtils)
    6.  
      HTTPResponse result = RecorderUtils.sendBy(request, req_data_json)
    7.  
      HTTPResponse result = RecorderUtils.sendBy(request, req_data_json)

    6、Ngringer的test运行次数设定(将总运行测试次数按百分比例分配到相应test):

    1.  
      1)引用依赖包:
    2.  
      import net.grinder.scriptengine.groovy.junit.annotation.RunRate
    3.  
      2)设置运行次数百分比(所有test设定的比例值不够100,那不满的部分不运行,比如设定总比80,只运行这80部分):
    4.  
      @RunRate(50) // 数字代表百分比
    5.  
      @Test
    6.  
      public void test1(){}
    7.  
      @RunRate(50) // 数字代表百分比
    8.  
      @Test
    9.  
      public void test2(){}

    7、Ngringer获取设置的加压机总数、进程总数、线程总数等信息:

    1.  
      int tota_agents = Integer.parseInt(grinder.getProperties().get("grinder.agents").toString()) // 设置的总加压机数
    2.  
      int total_processes = Integer.parseInt(grinder.properties().get("grinder.processes").toString()) // 设置的总进程数
    3.  
      int total_threads = Integer.parseInt(grinder.properties().get("grinder.threads").toString()) // 设置的总线程数
    4.  
      int total_runs = Integer.parseInt(grinder.properties().get("grinder.runs").toString()) // 设置的总运行次数(若设置的是运行时长,则得到0)

    8、Ngringer获取当前运行的加压机编号、进程编号、线程编号等信息(都从0递增):

    1.  
      int agent_number = grinder.agentNumber // 当前运行的加压机编号
    2.  
      int process_number = grinder.processNumber // 当前运行的进程编号
    3.  
      int thread_number = grinder.threadNumber // 当前运行的线程编号
    4.  
      int run_number = grinder.runNumber // 当前运行的运行次数编号

    9、Ngringer获取唯一递增值方法(从1递增,不重复):

    1.  
      // 传递接口参数runNumber(即def runNumber = grinder.runNumber)
    2.  
      private int getIncrementId(int runNumber){
    3.  
      // 获取压力机总数、进程总数、线程总数
    4.  
      int totalAgents = Integer.parseInt(grinder.getProperties().get("grinder.agents").toString())
    5.  
      int totalProcess = Integer.parseInt(grinder.getProperties().get("grinder.processes").toString())
    6.  
      int totalThreads = Integer.parseInt(grinder.getProperties().get("grinder.threads").toString())
    7.  
       
    8.  
      // 获取当前压力机数、进程数、线程数
    9.  
      int agentNum = grinder.agentNumber
    10.  
      int processNum = grinder.processNumber
    11.  
      int threadNum = grinder.threadNumber
    12.  
       
    13.  
      // 获取唯一递增数id
    14.  
      int incrementId = agentNum * totalProcess * totalThreads + processNum * totalThreads + threadNum + totalAgents * totalProcess * totalThreads * runNumber
    15.  
      return incrementId
    16.  
      }

    10、Ngringer根据唯一递增值获取参数化文件中的唯一行号:

    1.  
      1)需要设置静态变量:private enum WhenOutOfValues { AbortVuser, ContinueInCycleManner, ContinueWithLastValue }
    2.  
      2)传递接口参数fileDataList(即def fileDataList = new File(dataFilePath).readLines())
    3.  
      private int getLineNum(def fileDataList) {
    4.  
      // 获取当前运行数、数据读取行数、数据最大行数
    5.  
      int counter = getIncrementId(grinder.runNumber)
    6.  
      int lineNum = counter + 1
    7.  
      int maxLineNum = fileDataList.size() - 1
    8.  
       
    9.  
      // 读取最大值的判断处理
    10.  
      WhenOutOfValues outHandler = WhenOutOfValues.AbortVuser
    11.  
      if (lineNum > maxLineNum) {
    12.  
      if(outHandler.equals(WhenOutOfValues.AbortVuser)) {
    13.  
      lineNum = maxLineNum //grinder.stopThisWorkerThread()
    14.  
      } else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
    15.  
      lineNum = (lineNum - 1) % maxLineNum + 1
    16.  
      } else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
    17.  
      lineNum = maxLineNum
    18.  
      }
    19.  
      }
    20.  
      return lineNum
    21.  
      }

    11、Ngrinder日志输出配置的测试信息:(import java.text.SimpleDateFormat)

    1.  
      public static String getTestInfo(){
    2.  
      String time_string = ""
    3.  
      // 获取压测时设置的进程总数、线程总数、运行次数并在log中打印
    4.  
      int all_process = grinder.getProperties().getInt("grinder.processes", 1) // 设置的总进程数
    5.  
      int all_threads = grinder.getProperties().getInt("grinder.threads", 1) // 设置的总线程数
    6.  
      int all_runs = grinder.getProperties().getInt("grinder.runs", 1) // 设置的总运行次数(若设置的是运行时长,则得到0)
    7.  
      int all_duration = grinder.getProperties().getLong("grinder.duration", 1) // 设置的总运行时长(若设置的是运行次数,则得到0)
    8.  
      // 格式化时间毫秒输出(输出格式00:00:00)
    9.  
      SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss")
    10.  
      formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"))
    11.  
      String all_duration_str = formatter.format(all_duration)
    12.  
      if (all_duration_str.equals("00:00:00"))
    13.  
      time_string = "Test information: the processes is "+all_process+", the threads is "+all_threads+", the run count is "+all_runs+"."
    14.  
      else
    15.  
      time_string = "Test information: the processes is "+all_process+", the threads is "+all_threads+", the run time is "+all_duration_str+"."
    16.  
      return time_string
    17.  
      }

    12、Ngrinder打印所有的配置信息

    1.  
      String property = grinder.getProperties();
    2.  
      grinder.logger.info("------- {}", property) ;

    13、Ngrinder获取请求返回值:

    1.  
      HTTPResponse result = request.POST("http://192.168.2.135:8080/blogs", params, headers)
    2.  
      返回的文本:grinder.logger.info("----{}----", result.getText()) // 或者result.text
    3.  
      返回的状态码:grinder.logger.info("----{}----", result.getStatusCode()) // 或者result.statusCode
    4.  
      返回的url:grinder.logger.info("----{}----", result.getEffectiveURI())
    5.  
      返回的请求头所有参数:grinder.logger.info("---\n{}---", result)
    6.  
      返回的请求头某参数:grinder.logger.info("----{}---- ", result.getHeader("Content-type"))

    14、Ngrinder返回值的匹配:

    1.  
        匹配状态码:assertThat(result.getStatusCode(), is(200))
    2.  
      匹配包含文本:assertThat(result.getText(), containsString("success"))

    15、Ngrinder获取所有虚拟用户数:

    1.  
      public int getVusers() {
    2.  
      int totalAgents = Integer.parseInt(grinder.getProperties().get("grinder.agents").toString());
    3.  
      int totalProcesses = Integer.parseInt(grinder.getProperties().get("grinder.processes").toString());
    4.  
      int totalThreads = Integer.parseInt(grinder.getProperties().get("grinder.threads").toString());
    5.  
      int vusers = totalAgents * totalProcesses * totalThreads;
    6.  
      return vusers;
    7.  
      }
    
    

    16、Ngrinder的断言和error日志输出

    1.  
      if (result.statusCode == 301 || result.statusCode == 302) {
    2.  
      grinder.logger.error("Possible error: {} expected: <200> but was: <{}>.",result.getEffectiveURI(),result.statusCode);
    3.  
      } else {
    4.  
      assertEquals((String)result.getEffectiveURI(), result.statusCode, 200)
    5.  
      assertThat((String)result.getEffectiveURI(), result.statusCode, is(200))
    6.  
      }
     

    测试脚本示例

    nGrinder测试脚本

    import HTTPClient.HTTPResponse

    import HTTPClient.NVPair

    import net.grinder.plugin.http.HTTPPluginControl

    import net.grinder.plugin.http.HTTPRequest

    import net.grinder.script.GTest

    import net.grinder.scriptengine.groovy.junit.GrinderRunner

    import net.grinder.scriptengine.groovy.junit.annotation.AfterThread

    import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess

    import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread

    import org.junit.Test

    import org.junit.runner.RunWith

    import static org.junit.Assert.assertThat

    import static org.hamcrest.Matchers.is

    import static net.grinder.script.Grinder.grinder

    @RunWith(GrinderRunner)// 每个测试类加这注解

    class TestRunner{

        public static GTest test1

        public static HTTPRequest request

        @BeforeProcess// 在每个进程启动前执行

        static void beforeProcess() {

            HTTPPluginControl.getConnectionDefaults().timeout = 8000

            test1 = new GTest(3 ,"queryLoanCounts");

            request = new HTTPRequest()

        }

        @BeforeThread // 在每个线程执行前执行

        void beforeThread() {

            test1.record(this,"queryLoanCounts");

            // 延时生成报告

            grinder.statistics.delayReports=true;

        }

        private NVPair[] headers() {

            return [

                    new NVPair("Content-type""application/json;charset=UTF-8")

            ];

        }

        @Test

        public void queryLoanCounts(){

            String json = "{\"uid\": \"1_2000008\"}";

            HTTPResponse result = request.POST("http://core.com/query-loaning-count",json.getBytes(), headers());

            grinder.logger.info(result.getText());

            if (!result.statusCode == 200) {

                grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode);

            else {

                assertThat("判断响应结果:",result.statusCode, is(200));

            }

        }

        @AfterThread

        public void afterThread(){

        }

    }

    使用工具进行脚本的编写

    IDE编写测试脚本

    进程和线程的用法

    六、执行测试

    6.1、创建脚本

    6.2、 创建测试计划

    6.3、执行控制面板

    6.4、测试报告面板

    思考:

    为什么要部署多个agent?

    当线程数量过多的时候,实际的压力可能不会提升。由于agent本身的瓶颈,导致压力下发不下去。 当压力测试结果表现为:线程数量增多,响应时间和tps数却无变化,说明agent本身已经达到瓶颈了,无法再增加更多的压力。 这时候就需要部署多个agent给被测服务。

  • 相关阅读:
    今天是不是要得瑟那么一下下啦
    今天小小的总结一下最近的小程序中的问题
    敏感词过滤和XML的创建
    【腾讯优测干货分享】安卓专项测试之GPU测试探索
    【腾讯Bugly干货分享】WebVR如此近-three.js的WebVR示例解析
    【腾讯Bugly干货分享】Android动态布局入门及NinePatchChunk解密
    【腾讯Bugly干货分享】基于RxJava的一种MVP实现
    【腾讯Bugly干货分享】动态链接库加载原理及HotFix方案介绍
    【腾讯Bugly干货分享】微信iOS SQLite源码优化实践
    【腾讯Bugly干货分享】移动客户端中高效使用SQLite
  • 原文地址:https://www.cnblogs.com/ceshi2016/p/16500989.html
Copyright © 2020-2023  润新知