线程组
线程组作为JMeter测试计划的核心组件之一,对于模拟并发用户的行为至关重要。线程组元件是整个测试计划的入口,所有的取样器和控制器必须放置在线程组下。
可以将线程组视为一个虚拟用户池,其中每个线程可被理解为一个虚拟用户,多个虚拟用户同时执行相同的一批任务。
在这个虚拟用户池中,每个线程之间是相互隔离且互不影响的。每个线程的执行过程中,操作的变量不会对其他线程的变量值产生影响。
线程组的关键任务之一是定义并发用户的行为,包括设置线程数、循环次数、启动延迟等关键参数。通过适当配置线程组,测试人员可以模拟多用户在系统中同时执行任务的场景,从而评估系统的性能和稳定性。
通过灵活使用setup线程组、线程组、tearDown线程组、开放模型线程组,配置前置操作、主要操作、后置操作,更能真实、详细的评估系统。
线程组分为四类:
- 线程组
- setUp线程组
- tearDown线程组
- 开放模型线程组
线程组、setUp线程组、tearDown线程组控制面板中的元素基本一致:
- 名称、注释
- 在取样器错误后执行的动作
- 线程数
- Ramp-Up时间
- Same user on each iteration
- 延迟创建线程直到需要(只有线程组有)
- 调度器
开放模型线程组控制面板中的元素:
- 名称、注释
- 在取样器错误后执行的动作
- 调度计划
- 随机种子
执行顺序
在JMeter中,setUp线程组
拥有最高的优先级,而tearDown线程组
则具有最低的优先级。这一优先级关系可用表达式表示为:setUp线程组 > 线程组 = 开放模型线程组 > tearDown线程组
。
这意味着在测试计划执行过程中,setUp线程组
将首先执行,其后是线程组
和开放模型线程组
,最后执行tearDown线程组
。
通常情况下,setUp线程组
用于在测试执行之前进行一些初始化工作,而tearDown线程组
用于测试执行结束后的清理工作。
其他线程组在测试执行过程中按照它们在测试计划中的顺序执行。
示例接口代码
@ThreadGroup.route('/api/ThreadGroup/', methods=['GET', 'POST'])
def threadgroup1():
sleep(3) # 接口设置了休眠三秒,即接口在接收到请求数据三秒后,返回响应数据。
return "我是响应"
示例Jmeter脚本
-
在测试计划中,分别添加tearDown线程组、线程组、setUp线程组
-
在tearDown线程组、线程组、setUp线程组下分别添加HTTP请求取样器
名称分别为:
tearDown线程组
、线程组
、setUp线程组
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup1/
请求方式:
GET
-
在测试计划下添加查看结果树
演示内容
运行,查看结果树
可以观察到在2024-04-03 15:00:07
时,setUp线程组
中的取样器发送了请求。
随后,在 2024-04-03 15:00:10
时,线程组
中的请求取样器也发出了请求。
最后,在 2024-04-03 15:00:13
时,tearDown线程组请求取样器
发出了请求。
这与接口设置的休眠时间一致,表明 JMeter 先执行setUp线程组
,随后执行线程组
,最后执行 tearDown线程组
。即使脚本中的顺序不是这样。
Jmeter中线程组的执行顺序可以归纳为:setUp线程组
> 线程组
> 开放模型线程组
> tearDown线程组
。
线程数
线程组中的线程数指的是同时运行的虚拟用户数量。这个数量决定了你的测试将模拟多少个用户同时访问目标应用程序或服务。
在JMeter的线程组配置中,你可以根据你的需求来设置线程数,通常是根据你想要模拟的用户负载量和你的系统资源来决定的。
需要注意的是,线程数设置得太高可能会导致测试机器资源不足,影响测试结果的准确性;而设置得太低可能无法模拟真实的负载情况。因此,需要根据具体情况进行合理的设置。
示例接口代码
@ThreadGroup.route('/api/ThreadGroup2/', methods=['GET', 'POST'])
def threadgroup1():
return "我是响应"
示例Jmeter脚本
-
测试计划下,添加1个线程组
线程数:
3
-
在线程组下,添加HTTP请求取样器
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup2/
请求方式:
GET
-
在测试计划中,添加查看结果树
演示内容
运行,查看结果树
图中取样器结果中的Thread Name分别为线程组 1-1
、线程组 1-2
、线程组 1-3
。这是因为线程组
中线程数
值为3
,Jmeter启功了3个线程,每个线程皆执行1次线程组
。
在Jmeter中1个线程就代表1个用户,现在就相当于3个用户一起执行线程组
。
循环次数
在JMeter中,循环次数是指每个线程(即虚拟用户)执行其测试计划的次数。这个数量决定了你的测试将模拟用户访问目标应用程序或服务的次数。
在JMeter的线程组配置中,你可以根据你的需求来设置循环次数,通常是根据你想要模拟的用户访问上限值,如抽奖次数。
需要注意的是,循环次数设置得太高,特别设置循环次数为永远,可能会导致测试机器资源不足,影响测试结果的准确性;而设置得太低可能无法达到测试要求。因此,需要根据具体情况进行合理的设置。
示例接口代码
@ThreadGroup.route('/api/ThreadGroup2/', methods=['GET', 'POST'])
def threadgroup1():
return "我是响应"
示例Jmeter脚本
-
测试计划下,添加1个线程组
循环次数:
3
-
在线程组下,添加HTTP请求取样器
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup2/
请求方式:
GET
-
在测试计划中,添加查看结果树
演示内容
运行,查看结果树
图中取样器结果中的Thread Name皆为线程组 1-1
。这是因为线程组
中循环次数
值为3
,Jmeter启功了1个线程,连续执行了3次线程组
。
在Jmeter中1个线程就代表1个用户,现在就相当于1个用户执行了3次线程组
。
取样器错误后执行的动作
在JMeter中,取样器(Sampler)是用于模拟用户请求发送到目标服务器的组件,例如HTTP请求、FTP请求等。当取样器执行过程中出现错误时,可以通过配置相应的动作来处理这些错误。以下是一些处理取样器错误时,线程组中常见方式:
- 停止测试
- 立即停止测试
- 停止线程
- 启动下一进程循环
- 继续
通过合理配置这些错误处理方式,可以根据测试需求和场景来控制测试计划的行为,确保对错误有适当的响应和处理。
停止测试
设置取样器错误后执行的动作
为停止测试
时,一旦任何一个取样器遇到错误,整个测试计划将会在所有当前正在执行的线程执行完毕后停止。这可以用于模拟在测试过程中发生重要错误或异常时的行为。
这种设置确保在测试执行中任何关键的错误都会导致测试的终止,以便进行及时的识别和处理。这对于模拟真实世界中的异常情况以及确保测试的准确性和可重复性都是非常重要的。
示例接口代码
@ThreadGroup.route('/api/ThreadGroup3/', methods=['GET', 'POST'])
def threadgroup3():
if request.method == 'GET': # `错误请求`立即响应
return {'code': 200}
sleep(3) # 延长非`错误请求`的请求时间
return {'code': 200} # `非错误请求`延迟响应
单线程组
示例Jmeter脚本
-
测试计划下添加线程组
-
线程组下添加2个HTTP 请求取样器
名称:
错误请求
、正确请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
正确请求
的请求方式:POST
错误请求
的请求方式:GET
-
错误请求取样器下添加响应断言
值:
1111
-
在测试计划中,添加查看结果树
演示内容
运行,查看结果树
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行。错误请求
的结果报错后,因为设置取样器错误后执行的动作
为停止测试
,同时没有其他正在执行的线程,Jmeter直接结束本次测试。
删除响应断言,再次运行
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行。因为错误请求
的结果没有报错,会继续执行正确请求
。
多线程组
示例Jmeter脚本
-
测试计划下添加2个线程组
名称:
线程组1
、线程组2
-
线程组1下添加HTTP 请求取样器
名称:
错误请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
请求方式:
GET
-
线程组2下添加2个HTTP 请求取样器
名称:
与错误请求并行的正确请求
、错误请求之后的正确请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
请求方式:
POST
-
错误请求取样器下添加响应断言
值:
1111
-
错误请求之后的正确请求取样器下添加固定定时器(右键取样器-添加-定时器-固定定时器)
线程延迟:
3000
-
在测试计划中,添加查看结果树
固定定时器
可以延迟取样器的执行时间,设置为3
秒,可以确保错误请求之后的正确请求
在错误请求
结束后执行。
演示内容
运行,查看结果树
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行,线程组一般并发执行的。错误请求
的结果报错时,与错误请求并行的正确请求
也正在执行,错误请求之后的正确请求
还未执行。
因为设置取样器错误后执行的动作
为停止测试
,待与错误请求并行的正确请求
结束后不会执行错误请求之后的正确请求
,Jmeter直接结束本次测试。
此时,测试计划中未勾选独立运行每个线程组
。
勾选独立运行每个线程组
,再次运行
图中连续运行了5次,但是结果不符合预期。预期结果应该是不会执行线程组2
,但是执行了。应该是Jmeter的一个BUG(或许是独立运行每个线程组
的问题)。读者请谨慎使用。
立即停止测试
设置取样器错误后执行的动作
为立即停止测试
时,当取样器在执行过程中遇到错误时,JMeter会立即停止当前运行的测试,不再执行任何后续的请求或操作。
这有助于保护应用程序免受可能导致问题的异常或错误的影响,并确保测试结果的准确性。
这种设置对于测试场景中的稳定性和可靠性非常重要,特别是在模拟并发用户或大负载情况下,能够及时发现问题并停止测试,有助于减少潜在的影响和损害。
示例接口代码
@ThreadGroup.route('/api/ThreadGroup3/', methods=['GET', 'POST'])
def threadgroup3():
if request.method == 'GET': # `错误请求`立即响应
return {'code': 200}
sleep(3) # 延长非`错误请求`的请求时间
return {'code': 200} # `非错误请求`延迟响应
单线程组
示例Jmeter脚本
-
测试计划下添加线程组
-
线程组下添加2个HTTP 请求取样器
名称:
错误请求
、正确请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
正确请求
的请求方式:POST
错误请求
的请求方式:GET
-
错误请求取样器下添加响应断言
值:
1111
-
在测试计划中,添加查看结果树
演示内容
运行,查看结果树
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行。错误请求
的结果报错后,因为设置取样器错误后执行的动作
为立即停止测试
,Jmeter直接结束本次测试。
删除响应断言,再次运行
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行。因为错误请求
的结果没有报错,会继续执行正确请求
。
多线程组
示例Jmeter脚本
-
测试计划下添加2个线程组
名称:
线程组1
、线程组2
-
线程组1下添加HTTP 请求取样器
名称:
错误请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
请求方式:
GET
-
线程组2下添加2个HTTP 请求取样器
名称:
与错误请求并行的正确请求
、错误请求之后的正确请求
请求地址:
HTTP://127.0.0.1:5000/api/ThreadGroup3/
请求方式:
POST
-
错误请求取样器下添加响应断言
值:
1111
-
错误请求之后的正确请求取样器下添加固定定时器(右键取样器-添加-定时器-固定定时器)
线程延迟:
3000
-
在测试计划中,添加查看结果树
固定定时器
可以延迟取样器的执行时间,设置为3
秒,可以确保错误请求之后的正确请求
在错误请求
结束后执行。
演示内容
运行,查看结果树
图中连续请求了三次,结果是一致的。
取样器在线程组中一般是从上至下顺序执行,线程组一般并发执行的。错误请求
的结果报错时,与错误请求并行的正确请求
也正在执行,错误请求之后的正确请求
还未执行。
因为设置取样器错误后执行的动作
为立即停止测试
,不会等待与错误请求并行的正确请求
结束,Jmeter会直接结束本次测试,因此与错误请求并行的正确请求
的响应结果提示 Socket 关闭异常。
此时,测试计划中未勾选独立运行每个线程组
。
勾选独立运行每个线程组
,再次运行
图中连续运行了2次,但是结果不符合预期。预期结果应该是不会执行线程组2
,但是执行了。应该是Jmeter的一个BUG(或许是独立运行每个线程组
的问题)。读者请谨慎使用。
提示
本文示例接口源代码可从前言中下载。
评论区