Jmeter官网对逻辑控制器的解释是:“Logic Controllers determine the order in which Samplers are processed.”。
意思是说,逻辑控制器可以控制采样器(samplers)的执行顺序。由此可知,控制器需要和采样器一起使用,否则控制器就没有什么意义了。放在控制器下面的所有的采样器都会当做一个整体,执行时也会一起被执行。
JMeter逻辑控制器可以对元件的执行逻辑进行控制,除仅一次控制器外,其他可以嵌套别的种类的逻辑控制器。
JMeter中的Logic Controller分为两类:
(1)控制测试计划执行过程中节点的逻辑执行顺序,如:Loop Controller、If Controller等;
(2)对测试计划中的脚本进行分组、方便JMeter统计执行结果以及进行脚本的运行时控制等,如:Throughput Controller、Transaction Controller。
首先我们来看一下JMeter的逻辑控制器,路径:线程组(用户)->添加->逻辑控制器(Logic Controller);我们可以清楚地看到JMeter5中共有17个逻辑控制器,如下图所示:
如果上图您看得不是很清楚的话,宏哥总结了一个思维导图,关于JMeter5的逻辑控制器类型,如下图所示:
通过以上的了解,我们对逻辑控制器有了一个大致的了解和认识。下面宏哥就给小伙伴或则童鞋们分享讲解一些通常在工作中会用到的逻辑控制器。
4.1if Controller
在实际工作中,当使用Jmeter进行接口测试或者性能测试时,有时需要根据不同条件做不同的操作,为了解决这个问题,Jmeter提供了IF控制器。顾名思义,IF控制器实现了代码中IF的功能,通过判断表达式的True/False来判定是否执行相应的操作。通过条件判断下边的节点执行不执行。
1、我们先来看看这个if Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 如果 (if) 控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空。
Expression (must evaluate to true or false) :表达式(值必须是true或false),也就是说,在右边文本框中输入的条件值必须是true 或 false,(默认情况下)
Interpret Condition as Variable Expression?:默认勾选项,将条件解释为变量表达式(需要使用__jexl3 or __groovy 表达式)
Evaluate for all children?:条件作用于每个子项(具体理解宏哥会在后边实战篇列举例子说明),判断条件是否针对所有子节点,默认不勾选,只在if Controller的入口处判断一次。
注意:敲黑板!!!敲脑壳啦!!!
1、文本框上的黄色感叹号,就是提示你,建议采用__jexl3 or __groovy 表达式,以提高性能,也就是默认的方式。
2、if 控制器 只能作用于其下的子项
4.1.1默认用法
1、默认用法,就是采用__jexl3 or __groovy 表达式if 控制器下有一个 访问北京宏哥的博客园首页的取样器,只有if条件满足时,才会执行该取样器。采用默认方式,将条件'北京宏哥'=='北京宏哥',放入 __jexl3表达式中。如下图所示:
2、如果不知道表达式如何使用,可使用Jmeter 的函数助手,函数助手图标 > 选择_jexl3 > 在值的输入框输入'北京宏哥'=='北京宏哥' > 点击‘生成’ > 全选Ctrl+C复制 > Ctrl+V粘贴到表达式处 如下图所示:
3、配置好以后,运行JMeter,选择HTML,然后查看结果树,如下图所示:
4.1.2直接输入条件
1、直接输入只需要去掉 “Interpret Condition as Variable Expression?” 前面复选框,直接输入条件: '北京宏哥'=='北京宏哥' 。访问北京宏哥的博客园的首页的取样器将被执行。如下图所示:
2、配置好以后,运行JMeter,选择HTML,然后查看结果树,如下图所示:
4.13条件中使用变量
我们在日常工作中在很多的测试场景下,需要根据用户变量或者上一个取样器的返回值来进行条件判断,从而决定是否需要执行某一个的取样器。
1、首先我们新增一个用户变量:北京宏哥。条件:北京宏哥 的值为 宏哥 的时候,才执行访问北京宏哥博客园的首页的取样器。如下图所示:
用户变量及配置,如下图所示:
2、IF Controller及配置,或者可以用表达式:${__jexl3('${北京宏哥}'=='宏哥' ,)}。如下图所示:
4.1.4Evaluate for all children? 的用法
1、宏哥在上面的小节中讲解和分享了在条件中如何使用变量,我们假设一种测试场景:如果 if 控制器下的取样器执行后,改变了该变量的值,if 控制器下 其后的取样器还会被继续执行吗?跟随宏哥一起来看看下面的列子:
2、改变“北京宏哥”变量的值为“北京宏哥”,如下图所示:
3、JMeter执行过程的逻辑分析:
(1) if 控制器下 有 3 个取样器,变量 北京宏哥 的初始值为 宏哥,if 控制器的条件为:${__jexl3("${北京宏哥}"=="宏哥",)}。
(2)开始执行的时候满足条件,那么按理说应该执行 访问博客园首页 、访问北京宏哥的博客园首页、访问宏哥的JMeter系列文章 3个取样器,
(3)但是 访问北京宏哥的博客园首页 执行后,将 北京宏哥 的值变了 北京宏哥,已经不能满足 "${北京宏哥}"=="宏哥" 条件。
(4)所以 访问宏哥的JMeter系列文章 这个取样器不会被执行。
4、运行JMeter,查看结果树,对比运行结果和宏哥分析的一致,如下图所示:
5、如果这个时候,去掉 Evaluate for all children? 的勾选,会发生什么呢,大家可以自己动手试试。修改后记得点击“保存”。下边是宏哥的执行结果,如下下图所示:
另外,如果时字符串必须要用引号,变量都认为是字符串的形式,如:${__jexl3("${北京宏哥}"=="宏哥",)}。
4.2Transaction Controller
事务响应时间是我们衡量业务性能的主要指标,事务控制器可以把其他节点下的取样器执行消耗时间累加在一起,便于统计。同时对每一个取样器的执行时间进行统计。
如果事务控制器下的取样器有多个,只有当所有的取样器都运行成功,整个事务控制器定义的事物才算成功。
用于将Test Plan中的特定部分组织成一个Transaction,JMeter中Transaction的作用在于,可以针对Transaction统计其响应时间、吞吐量等。比如说,一个用户操作可能需要多个Sampler来模拟,此时使用Transaction Controller,可以更准确地得到该用户操作的性能指标,如响应时间等。这个时间包含该控制器范围内的所有处理时间,而不仅仅是采样器的。
这个就非常有用了。我们前面有提到过事务的概念,有时候我们不关心单个请求的响应时间,而是关心一组相关请求的整体响应时间,怎么来统计呢?就需要借助事务这个概念,把这组请求,放到一个事务控制器下面。
1、我们先来看看这个Transaction Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 事务控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
generate parent sample:选择是否生成一个父取样器;
include duration of timer and pre-post processors in generated samle:是否包含定时器,选择将在取样器前与后加上延时。(宏哥建议大家不要勾选,否则统计就比较麻烦了,还需要你扣除延时)
4.2.1generate parent sample用法
1、宏哥列举一个测试场景:我们需要了解 访问博客园首页 访问北京宏哥的博客园首页这两个请求的单个请求的响应时间,那么就来看看如下实例。
(1)单个请求,那么不勾选generate parent sample,如下图所示:
2、运行JMeter,查看聚合报告的单个请求的响应时间,如下图所示:
1、宏哥列举一个测试场景:我们需要了解 访问博客园首页 访问北京宏哥的博客园首页这两个请求作为一组请求的响应时间,那么就来看看如下实例。
(1)一组请求,那么勾选generate parent sample,如下图所示:
2、运行JMeter,查看聚合报告的一组请求的响应时间,如下图所示:
4.3Loop Controller
循环控制器可以控制在其节点下的元件的执行次数,可以是具体数字,也可以是变量。
1、我们先来看看这个Loop Controller长得是啥样子,默认循环一次。路径:线程组 > 添加 > 逻辑控制器 > 循环控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Forever:勾选上这一项表示一直循环下去。
注意:敲黑板,敲脑壳!!!
如果同时设置了线程组的循环次数和循环控制器的循环次数,那循环控制器的子节点运行的次数为两个数值相乘的结果。
4.3.1Thread Group和循环控制器的区别
1、现在宏哥准备两个请求,设置线程组1个线程,5次loop,下边有一个请求:访问北京宏哥的博客园首页 一个Loop Controller(设置2次loop),下边有一个请求:访问博客园首页
(1)线程组,如下图所示:
(2)循环控制器,如下图所示:
2、运行JMeter,查看结果树,为了清楚地看出结果,宏哥将第一个请求故意配置成失败的;如下图所示:
从上边的结果可以看出:
(1)如果同时设置了线程组的循环次数和循环控制器的循环次数,那循环控制器的子节点运行的次数为两个数值相乘的结果。
(2)运行顺序是:先执行线程组里的循环,再执行循环控制器里的循环。
4.4While Controller
While条件控制器,其节点下的元件将一直运行直到While 条件为false。
1、我们先来看看这个While Controller长得是啥样子,默认循环一次。路径:线程组 > 添加 > 逻辑控制器 > While控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Condition:接受变量表达式与变量。条件为 Flase 的时候,才会跳出 While 循环,否则一直执行 While 控制器下的元件。
3、While控制器提供三个常量
(1)Blank:当循环中最后一个取样器失败后停止
(2)LAST:当循换前有取样器失败,不进入循环
(3)Otherwise:当判断条件为false时,停止循环
4.4.1Blank
1、不填(空):当 While 控制器下最后一个样例执行失败后 跳出循环,如下图所示:
2、运行JMeter,查看结果树,(你可以通过鼠标拖动最后失败的取样器,移动到第一个或者第二个位置的时候,运行JMeter后,会发现在一直运行);如下图所示:
4.4.2LAST
LAST :当 While 控制器下最后一个样例执行失败后 跳出循环,如果 While 控制器 前一个样例执行失败,则不会进入While循环,也就是不会执行While控制器下的样例。
1、取样器树还是上边的位置和顺序。这次我们在While控制器表达式处填写:LAST,如下图所示:
2、运行JMeter,查看结果树,(你可以通过鼠标拖动最后失败的取样器,移动到第一个或者第二个位置的时候,运行JMeter后,会发现在一直运行);细心的你可以发现循环只跑一遍,与不填 的结果是一样的如下图所示:
3、但是输入LAST的时候,还会出现一个结果,那就是:如果While 控制器 的前一个样例执行失败,则不会进入While 控制器
在While 控制器 前面 添加两个取样器:取样器1 访问百度,取样器2 访问北京宏哥 使取样器2 访问北京宏哥 执行失败。取样器2必须在While控制器前边且执行失败。如下图所示:
4、运行JMeter,查看结果树,执行结果发现,取样器1、取样器2 执行了,但没有进入While 控制器,如下图所示:
4.4.3Otherwise
自定义条件:值为True 或 False的函数/变量/属性 表达式;类似前边讲解的IF控制器,宏哥这里就照猫画虎的举个例子。
1、用户自定义变量,变量名:北京宏哥,变量值:true,如下图所示:
2、While控制器配置,取到变量的值:${北京宏哥},填写到表达式的地方,如下图所示:
3、JMeter执行过程的逻辑分析:
(1)北京宏哥用户(线程组)下 有 1 个用户自定义变量,变量 北京宏哥 的值为 true,While控制器的条件为:${北京宏哥} 取到的值始终是 true。
(2)所以一旦开始执行始终满足条件,那么按理说就应该一直执行 访问博客园首页 、访问北京宏哥的博客园首页、访问宏哥的JMeter系列文章 3个取样器,
4、运行JMeter,查看结果树,(运行JMeter后,会发现在一直运行),对比一下,与宏哥的分析是不是高度一致哈;如下图所示:
4.1Critical Section Controller
我们先来看一下,官方原汁原味的解释:The Critical Section Controller ensures that its children elements (samplers/controllers, etc.) will be executed by only one thread as a named lock will be taken before executing children of controller.
宏哥这个二把刀的翻译,给你们翻译一下这段鸟语看看到底是什么意思,大致意思是: Critical Section Controller(临界区控制器),确保它的子元素(samplers /控制器等)在执行控制器的子程序之前只执行一个线程作为指定的锁。呵呵!看到这句话是不是觉得一头雾水啊,摸一摸自己所剩无几的头发陷入沉思中.....没有关系的,不要纠结了,宏哥后边会用具体实例讲解一下,看完实例后,再回过头来阅读这句话,你就会恍然大悟了。
1、我们先来看看这个Critical Section Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 临界部分控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Lock name:锁名称,这里可以填入其子节点下执行的线程的名称,这个线程作为一个全局锁存在
4.1.1实例讲解
这部分主要是通过配合实例我们来理解一下开始那句话到底什么意思。
1、宏哥这里先说一个访问宏哥博客园的JMeter系列文章的测试场景:我们第一步首先要访问博客园的首页,第二步找到宏哥的访问宏哥博客园的首页,第三步点击JMeter类别。按顺序完成三步,才能完成这个测试场景。那么我们根据这个场景用JMeter来添加多个请求的取样器。如下图所示:
2、脚本调试是通了,运行JMeter,查看结果树,如下图所示:
3、从上个图,查看结果树中显示请求结果数据不是按照顺序请求,不符合预期,这个时候增加一个critical section controller(临界部分控制器),增加一个锁,就能控制执行顺序。如下图所示:
4、脚本调试是通了,运行JMeter,查看结果树,可以清楚地看出来是按预期的顺序执行请求的。但是这样响应时间会过长,这个后边再做讲解。如下图所示:
4.1.2锁名分类
(1)锁名为空,认为每个锁为不同的锁
1、宏哥通过具体实例,来看一下,创建锁名为空的临界部分控制器,如下图所示:
2、运行JMeter,查看结果树,如下图所示:
(2)锁名相同,多个锁认为是同一个锁,同一个时间点只能存在一个运行中
1、宏哥通过具体实例,来看一下,创建锁名相同的临界部分控制器,如下图所示:
2、运行JMeter,查看结果树,如下图所示:
(3)锁名为变量,根据变量值来判断是不是属于同一个锁,变量值为相同时,则认为是同一个锁
1、宏哥通过具体实例,来看一下,创建锁名为变量的临界部分控制器,如下图所示:
2、运行JMeter,查看结果树,如下图所示:
4.2ForEach Controller
ForEach 控制器:一般搭配用户变量使用。依次调用用户定义的变量,直到最后一个,结束循环。为了满足ForEach Controller提取数据,变量命名的格式一般为“变量名_数字”,其中数字从1开始。
1、即遍历循环控制器,顾名思义是定义一个循环规则。
2、用来遍历当前元素的所有可执行场景。
3、在用户自定义变量中读取一系列相关的变量,该控制器下的采样器或控制器都会被执行一次或多次,每次读取不同的变量值。
4、这个控制器一般配合配置元件 → 正则表达式提取器来一起使用,可对页面上的某些元素进行重复处理。
1、我们先来看看这个ForEach Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > ForEach控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Input variable prefix:输入变量前缀,可以在“用户自定义变量”中定义一组变量,循环控制器可以从中获取到变量对应的值,然后作为循环控制器的循环条件,还可以输出变量作为取样器的参数。
Start index for loop:循环变量下标起点。循环指数开始(唯一)→ 遍历查询的变量范围,开始的值(这里如果不填写,默认从 1 开始,如果没有 1 开始的变量,执行时会报错)
End index for loop:循环变量下标终点。循环指数结束(包含)→ 遍历查询的变量范围,结束的值
Output variable name:输出变量名称,循环控制器生成的变量名称。后续可通过${}引用
Add "_" before number ?: 变量前缀后是否加“_”作为分隔符。如果定义的变量名中有下划线的话就要勾选此项,否则找不到;反之,没有的话不要勾选,否则同样找不到变量
4.2.1实例讲解
1、首先在自定义5个前缀为 北京宏哥 的变量,值分别为 a b c d e。并且 北京宏哥 后面的数字是连续的,如果不连续,则不会被循环到,如下图所示:
2、配置ForEach控制器,如下图所示:
3、添加请求 访问博客园首页 + 输出值:${宏哥},输出值是在控制器的输出变量 宏哥,通过 ${宏哥} 取到输出变量的值,如下图所示:
4、添加查看结果树,运行JMeter,查看结果树,如下图所示:
注意:敲黑板,敲脑袋!!!
1、输入变量的后缀数值一定要连续,比如 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 ... 这样,如果中间有不连续的,循环会中断
2、循环开始的设定:如果变量为北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而设定的开始为 1,则会从北京宏哥_2 开始循环
3、循环结束的设定:如果变量有3个 北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而设定的结束为5,则只会循环 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 ,如果设定的结束为2,则会循环 北京宏哥_1, 北京宏哥_2 。
4.3Include Controller
Include控制器用来导入外部的测试片段(非完整的测试计划),在执行时会执行导入的测试计划,但是被导入的测试计划有特殊要求,它不能有线程组,只能包含简单的控制器及控制器下的元件。换句话说就是相当于加了一个执行单元,一个封装了的业务操作单元,类似我们程序开发中的函数(方法)一样。例如一个查询学生信息的业务操作我们用取样器来模拟,然后放到简单控制器中作为一个执行单元,别的地方也要用到时,我们可以不用重复造轮子直接引用过来。
一般来说,Include控制器和测试片段(Test Fragment)配合使用的比较常见。
1、我们先来看看这个include Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > Include控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Filename:文件名,必输字段,如果没有,就会报错。通过Filename的路径和文件名引用外部的jmx文件。
宏哥推荐小伙伴或者童鞋们可以将 Include控制器 与 Module控制器(传送门)一起对比着学习,Include控制器 是从外部文件引用,只能引用整个测试片段的内容,Module控制器 是从内部文件中引用,引用上相对比较灵活,可以只引用部分测试片段或模块内容。这样一内一外不仅容易理解也容易记忆和学习。
4.3.1实例
(1)当Filename路径的值为空,程序执行报错,脚本执行中止,不会继续执行下面的脚本内容。
1、首先创建一个Filename路径为空的测试计划,如下图所示:
2、运行JMeter,查看结果树(程序执行报错,脚本执行中止,不会继续执行下面 访问博客园首页 的取样器),如下图所示:
(2)当Filename路径中的文件不存在,程序直接弹窗报错并停止执行。
1、首先创建一个Filename路径中的文件不存在的测试计划,点击“保存”按钮的时候,就会直接弹窗报错。如下图所示:
(3)当Filename路径的文件中不包含测试片段,跳过控制器,继续向下执行。
1、首先创建一个外部引用没有测试片段的测试计划,如下图所示:
2、创建一个Filename路径的文件中不包含测试片段的测试计划,将上边的外部引用-无测试片段文件添加到Include控制器中,如下图所示:
3、运行JMeter,查看结果树(跳过控制器,继续向下执行 访问博客园首页 的取样器),如下图所示:
(3)当Filename路径的文件中包含测试片段,执行完控制器,再继续向下执行。
1、首先创建一个外部引用有测试片段的测试计划,如下图所示:
2、创建一个Filename路径的文件中包含测试片段的测试计划,将上边的外部引用-有测试片段文件添加到Include控制器中,如下图所示:
3、运行JMeter,查看结果树(执行完控制器里的测试片段,再继续向下执行 访问博客园首页 的取样器),如下图所示:
到这里,大家应该理解了 Include Controller 和 Test Fragment 了吧。宏哥的理解就是,Test Fragment 相当于一个独立的部分,可以被其他测试计划引用,实现 样例的片段化,模块化,遇到重复需要的,比如登录、注册之类的,就可以用Test Fragment 和 Include Controller 了。这样可以避免重复造轮子,做许多无用功。
4.1Interleave Controller
交替控制器,顾名思义是:互相交替,其节点下的取样器交替执行。根据被控制器触发执行次数,去依次执行控制器下的子节点<逻辑控制器、采样器>。被触发执行可以由线程组的线程数、循环次数、逻辑控制器触发。
1、我们先来看看这个Interleave Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 交替控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Ignore sub-controller blocks:忽略子控制器,即子控制器失效,由交替控制器接管。
勾选后,会无视节点下的所有控制器<交替控制器、随机控制器例外>,将每个取样器作为一个单独字节点执行
不勾选忽略子控制器,交替执行时,节点下次一级每个取样器、逻辑控制器都认为是一个单独子节点来交替执行。
Interleave across threads: 勾选此项,则交替控制器下的请求将应用至所有线程和循环中迭代。如有四个请求,三个线程,两轮循环,那么第一轮三个线程分别运行请求1,请求2,请求3,第二轮循环的三个线程运行请求4,请求1,请求2。
允许跨线程交替执行,勾选后,当线程组线程数大于1时,当前线程首次执行会根据线程数顺序进行交替,后续执行按自己所属线程的上一个次的执行的位置交替,如: 交替控制器下由A B C D E 5个接口, 设置线程组 线程数3个,循环4次,则最终执行结果为 线程1执行 A B C D 线程2执行 B C D E 线程3执行 C D E A 。
4.1.1简单实例
1、首先在交替控制器下添加3个取样器 访问博客园首页、访问北京宏哥的博客园首页和访问北京宏哥的JMeter系列文章,线程组下添加一个取样器 访问度娘,与交替控制器同层级,线程组设置循环次数为2,如下图所示:
2、配置好以后,运行JMeter,然后查看结果树(循环两次,每次只执行交替控制器里一个取样器),如下图所示:
4.1.2复杂实例
宏哥这里讲解的复杂使用,就是将交替控制器嵌套使用,来看看执行结果,从而更进一步的理解和学习交替控制器。
1、创建一个父交替控制器:北京宏爸,其下两个子交替控制器:北京宏哥 和 北京宏弟,子交替控制器下面分别添加2个取样器:访问度娘 和 访问博客园首页,设置线程组循环次数10,如下图所示:
2、配置好以后,运行JMeter,然后查看结果树( 从结果可以看出,先交替子控制器的样例,再交替父控制器下的样例。大家明白了吧),如下图所示:
4.1.3忽略子控制器块
在交替控制器的设置界面,有这样一个选项,是否忽略子控制器,所以这里一般也是交替控制器作为父级控制器时使用的选项,这里的子控制器一般指非交替控制器的其他控制器 (如果子控制器也是交替控制器,该项实际和交替控制器的嵌套效果一样了)
1、下面,我们在交替器下添加一个循环控制器,设置循环次数 2,线程组循环次数设置为 3,设置交替器 勾选 忽略子控制器,如下图所示:
循环控制器:
线程组:
交替控制器:
2、 配置好以后,运行JMeter,然后查看结果树( 从结果可以看出,循环控制器没有执行2次,只执行了1次),如下图所示:
3、下面,我们再把交替控制器中 忽略子控制器 去掉勾选,其他设置不变,如下图所示:
4、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,循环控制器执行2次,然后再执行 访问度娘-哥弟 取样器这样交替执行了3次),如下图所示:
综上所述:以控制器为1个小单元,交替执行。
4.2Once Only Controller
在每个线程内,该控制器下的内容只会被执行一遍,无论循环多少次,都只执行一遍。<嵌套在循环控制器之内时是个例外,每个线程组循环都会被执行一遍>。
此控制器通常用于控制需要登录的请求,测试过程中,我们往往都只需要登录一次,获取到对应的登录信息后即可执行后续相关的请求,而不是每执行一个请求都登录一次,如将login请求放入仅一次控制器,则在线程组循环运行期间,不论循环次数设置为多少次,login请求都将仅在第一次执行时运行
1、我们先来看看这个Once Only Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 仅一次控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空。
4.2.1实例
宏哥这里以博客园发布文章为例,说一下测试场景:正常逻辑是我们需要一次登录博客园然后多次发布文章;而不是发布一次文章就需要登录一次博客园。以此为例添加测试脚本。
1、按照上边的测试场景,宏哥添加测试脚本,如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,一次登录博客园然后多次发布文章;而不是发布一次文章就需要登录一次博客园),如下图所示:
4.2.2红色字体实战举例
<嵌套在循环控制器之内时是个例外,每个线程组循环都会被执行一遍>。
1、保持上边的测试树结构,然后将 仅一次控制器 用鼠标拖到 循环控制器 里边,如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了3个线程,每个线程都登录一次博客园),如下图所示:
4.3Random Controller
随机控制器节点下的元件随机运行,与交替控制器不一样的是节点下的元件运行顺序不定。
1、我们先来看看这个Random Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 随机控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Ignore sub-controller blocks:忽略子控制器,即子控制器失效,由随机控制器接管,类似交替控制器。
4.3.1简单实例
1、创建测试计划,随机控制下添加三个请求,控制器外一个请求,线程4个;如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了4个线程,每个线程都要访问一次北京宏哥的Jmeter系列文章,但是控制器下边的取样器的访问却是随机访问一个),如下图所示:
4.3.2随机嵌套循环-不忽略子控制器
1、按照小标题的内容,创建测试计划,如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了3个线程,随机选择随机控制器下的两个循环控制器),如下图所示:
4.3.3随机嵌套循环-忽略子控制器
1、按照小标题的内容,创建测试计划,如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了3个线程,循环控制器也失效了,每次都随机选择一个取样器执行),如下图所示:
4.3.4随机嵌套交替-忽略子控制器
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了10次循环,交替控制器也失效了,每次都随机选择一个取样器执行),如下图所示:
4.4Random Order Controller
随机顺序控制器其节点下的原件随机执行,不过每个元件只执行一次。
当控制器被触发时,将控制器下的所有子节点顺序打乱执行一遍,执行一遍;执行一遍,不是执行一个。
注意:是将子节点的顺序打乱,而非请求的顺序打乱,子节点可以是其他逻辑控制器。
随机控制器与随机顺序控制器名字十分接近,但两者还是有着明显的区别,可参考 上边介绍的随机控制器。
随机控制器为每次只执行节点下的一个子节点,随机顺序控制器是将节点下的所有子节点都正常执行,只是将执行顺序打乱
1、我们先来看看这个Random Order Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 随机顺序控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空。
4.4.1实例
1、创建测试计划,如下图所示:
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树( 从结果可以看出,宏哥设置了3次循环,每次循环把所有的子节点都执行了),如下图所示:
4.5Recording Controller
其录制控制器,顾名思义是录制的时候会用到。实际上它是一个位置,当我们用JMeter代理进行录制时,录制的脚本默认放在此控制器的节点下面。没有实际的逻辑作用,我们用简单控制器也可以代替它。由于这个没有用到过,这里宏哥就不做详细介绍了,如果后期用到的话,宏哥会单独写一篇关于录制控制器的文章给小伙伴或童鞋们来答疑解惑。
1、我们先来看看这个Recording Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 录制控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Forever:勾选上这一项表示一直循环下去。
4.1Runtime Controller
运行控制器用来控制其子元件的执行时长。市场单位是秒。
1、我们先来看看这个Runtime Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 运行控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Runtime:默认为1,去掉1则默认为0,此时不执行其节点下的元件。 与线程组中的调度器的持续时间 效果一致。不填 或 0,不会执行样例
4.1.1Runtime控制器控制其下取样器执行2s
1、创建测试计划,设置 Runtime 控制器的运行时间 为 2,线程组设置默认不变,如下图所示:
Runtime 控制器设置
线程组设置
2、配置好以后,运行JMeter,然后查看结果树,如下图所示:
4.1.2使用线程组中的调度器控制样例运行3s
1、创建测试计划,设置 Runtime 控制器的运行时间 为 2,线程组设置运行时间3,如下图所示:
线程组设置
Runtime 控制器设置
2、配置好以后,运行JMeter,然后查看结果树,如下图所示:
线程组设置3,Runtime控制器设置2,但是运行时间是2s。所以从上边的运行时间得出结论:如果线程组中设置了持续时间,Runtime 控制器也设置了 运行时间,那么会优先于线程组中的设置。
4.2Simple Controller
Simple Controller用来指定了一个执行单元,它不改变元件的执行顺序。在它下边还可以嵌套其他控制器。简单控制器可以编辑只有名称和注释。就像他的名字一样,简单,可以理解为一个文件夹,就是分组用的,没有其他特殊功能,但相比不添加简单控制器,区别在于简单控制器可以被模块控制器所引用。其作用就是分组,比如QQ好友列表,可分为家人、同学、等。一般是请求较多,需要分组时采用。
1、我们先来看看这个Simple Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 简单控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空。
4.2.1简单实例
1、创建测试计划,线程组设置循环10,如下图所示:
2、配置好以后,运行JMeter,然后查看结果树,如下图所示:
4.3Throughput Controller
用来控制其下元件的执行次数,并无控制吞吐量的功能,想要控制吞吐量可以使用Constant Throughput Timer,后边会讲解到。吞吐量控制器有两种模式:Total Executions:设置运行次数与Percent Executions:设置运行比例(1~100之间)。
1、我们先来看看这个Throughput Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 吞吐量控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Total Executions:执行百分比(1-100);
percent Executions:执行数量;
Throughput:根据上边选择的方式填写,百分比为0~100;
Per User:线程数,当选Total Executions时,是线程数;当选percent Executions时,是线程数*循环次数。
4.3.1不勾选Per User
1、线程组中设置 线程数量 2,循环次数 10,吞吐量控制器 设置 Total Executions,吞吐量设置为 2,其下添加一个取样器,如下图所示:
2、配置好以后,运行JMeter,然后查看结果树(执行了2次),如下图所示:
3、现在将 吞吐量控制器 设置为百分比的控制方式,吞吐量设置为:50%,如下图所示:
4、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了10次,计算方式:10=吞吐量50% * 循环次数10 * 线程数 2),如下图所示:
4.3.2勾选Per User
1、线程组中设置 线程数量 2,循环次数 10,吞吐量控制器 设置 Total Executions,吞吐量设置为 2,其下添加一个取样器,勾选Per User,如下图所示:
线程组设置
吞吐量控制器
2、配置好以后,点击“保存”,运行JMeter,然后查看结果树(总共执行了4次,其中吞吐量设置为2,执行2次,线程设置为2,执行2次,总共4次),函数 __threadNum 只是简单地返回当前线程的编号,如下图所示:
3、现在将 吞吐量控制器 设置为百分比的控制方式,吞吐量设置为:50,如下图所示:
4、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了10次,计算方式:10=吞吐量50% * 循环次数10 * 线程数 2),如下图所示:
综上所述:
勾选Per User:
1.线程数*循环次数>=线程数*吞吐量时,Total Executions模式的执行次数=线程数*吞吐量。
2.线程数*循环次数<线程数*吞吐量时,Total Executions模式的执行次数=当线程数*循环次数。
不勾选Per User:
1.线程数*循环次数<=吞吐量时,Total Executions模式的执行次数=线程数*循环次数。
2.线程数*循环次数>吞吐量时,Total Executions模式的执行次数=吞吐量。
l Percent Executions:设置运行比例(1~100之间),单位为%
不管Per User是否勾选,按Percent Executions模式的执行次数都不受Per User影响,Percent Executions模式的执行次数=线程数*循环次数*吞吐量%。(循环次数=线程组循环次数*循环控制器循环次数)
l Per User:勾选该项的话则按虚拟用户数(线程数)来计算执行次数,不勾选则按所有虚拟用户数来计算执行次数
序号 | 线程数 | 循环次数 | 模式 | Throughput | Per User | 执行次数 |
1 | 2 | 10 | Percent | 50 | Y | 10 |
2 | 2 | 10 | Percent | 50 | N | 10 |
3 | 2 | 10 | Total | 7 | Y | 14 |
4 | 2 | 10 | Total | 7 | N | 7 |
5 | 2 | 2 | Total | 7 | Y | 4 |
6 | 2 | 2 | Total | 7 | N | 4 |
下面说明一下这6个场景:
(1)序号1和2场景,Per User 对总执行次数没有影响。
(2)序号3场景,Per User勾选,每个虚拟用户(线程)执行7次,共执行14次。
(3)序号4场景,Per User不勾选,则所有虚拟用户执行7次。
(4)序号5场景,Per User勾选,每个虚拟用户(线程)执行7次,共执行14次,由于Thread Group计划循环次数是4(2线程*2循环)次,所以最多只能执行4次。
(5)序号6场景,Per User不勾选,所有虚拟用户执行7次,由于Thread Group计划循环次数是4(2线程*2循环)次,所以最多只能执行4次。
4.4Module Controller
模块控制器可以快速的切换脚本,不用来回的新建,方便脚本调试。
可以理解为引用、调用的意思,执行内容为Module To Run种所选的内容,引用范围为当前测试计划内的测试片段、逻辑控制器<模块控制器除外>
被引用的逻辑控制器、测试片段可以为禁用状态,被引用后仍然会被执行。
可以将模块控制器与包括控制器一起学习比较,模块控制器是从内部文件中引用,引用上相对比较灵活,可以只引用部分测试片段或模块内容,包括控制器是从外部文件引用,只能引用整个测试片段的内容。
注意:被应用的模块位置不可随意变更,变更后会执行时出现提示引用失败
找到目标元素:快速查找与跳转的作用,点击后会立即跳转到所选的逻辑控制器的内容详情
1、我们先来看看这个Module Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 模块控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Forever:勾选上这一项表示一直循环下去。
4.4.1实例
1、创建测试计划,添加两个测试片段,并且在每个测试片段下添加一个取样器,然后,添加线程组,再添加模块控制器,最后添加查看结果树,如下图所示:
2、配置模块控制器,选择第一个测试片段,如下图所示:
3、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了第1个测试片段的取样器),如下图所示:
4、配置模块控制器,选择第二个测试片段,如下图所示:
5、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了第2个测试片段的取样器),如下图所示:
4.5Switch Controller
Switch Controller:开关控制器,通过其下样例顺序数值或名称 控制执行某一个样例。
1、我们先来看看这个if Controller长得是啥样子,路径:线程组 > 添加 > 逻辑控制器 > 如果 (if) 控制器,如下图所示:
2、关键参数说明如下:
Name:名称,可以随意设置,甚至为空;
Comments:注释,可随意设置,可以为空;
Switch Value:指定请求的索引或者名称,索引从0开始,如果没有赋值,或者索引超过请求个数的话就执行第0个请求。可以是数字,也可以是字符,为字符时匹配取样器名称,如果匹配不上就会默认并找取样器名称为default的取样器,如果没有则不运行。
4.5.1数值
数值:表示将执行其下第 数值+1个取样器,例如:填1,将执行第2个取样器;填0或者不填,将执行第1个取样器;数值超出其下取样器数目时,执行第1个取样器。
1、创建一个测试计划,设置线程组和Switch控制器,如下图所示:
线程组
Switch控制器
2、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了第3<数值+1>个取样器),如下图所示:
3、修改Switch控制器的数值为0或者不填,如下图所示:
4、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了第1<数值为0或者不填,执行第1个取样器>个取样器),如下图所示:
4.5.2字符
1、创建一个测试计划,设置线程组和Switch控制器(直接使用取样器名字),如下图所示:
线程组
Switch控制器
2、配置好以后,点击“保存”运行JMeter,然后查看结果树(执行了使用名字的取样器),如下图所示: