我们经常使用 cron 表达式来定义定时任务的执行策略,今天我们就总结一下 cron 表达式的一些相关知识。

cron表达式定义

cron 表达式共有 7 个字段,包括 Seconds、Minutes、Hours、Day of mouth、Mouth,、Day of week,、Year,每一个字段代表一个含义

Seconds Minutes Hours Day of mouth Mouth Day of week [Year]
[年]

其中Year是可选的

各字段的允许值及允许字符

字段名 允许值 允许的特殊字符
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day of mouth 1-31 , - * / ? L W
Mouth 1-12 or JAN-DEC , - * /
Day of week 1-7 or SUN-SAT , - * / ? L #
Year 不填 or 1970-2099 , - * /

特殊字符的含义

* :匹配该字段允许的任意值,如果该字符在秒的位置处,表示每秒都会触发事件

- :表示范围,如果在分钟的位置处使用 5-20,即从第 5 分钟到第 20 分钟每分钟触发一次

/ :表示触发的起始时间和间隔时间,如果在分钟位置使用 5/20 ,即从第 5 分钟开始每隔 20 分钟触发一次(5、25、45分分别触发一次)

, :表示列出枚举值,如果在分钟位置使用 5, 20 ,即在第 5 和第 20 分钟各触发一次

? :只能用在 Day of mouth 和 Day of week 字段中,表示忽略任意值,因为这两个字段值可能会发生冲突,当其中一个值被指定后,需要忽略另一个来避免冲突。(比如20号不一定是周一)

L (last) :表示最后,在 Day of mouth 字段中表示”这个月最后一天”,在 Day of week 字段如果配合数字使用 ,如5L,表示”该月的最后一个星期四”

W (weekday) :表示最接近指定天的工作日(周一到周五),比如 15W,指最近接本月第15天的工作日,如果那天是周六,则在那周五即前一天触发事件,如果那天是周日,则在下周周一触发事件,如果那天是在周一到周五的范围内,则在当天触发。

LW(last weekday) :这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

# :只能用在 Day of week 字段中,表示该月的第几个周几,如 6#3 表示第3个周五(3 表示第 3 个,6 表示周五),如果指定日期不存在,事件不会触发

cron表达式例子

cron表达式 含义描述
0 0 0 * * ? 每天执行
0 0 12 * * ? 每天12点触发
0 15 16 * * ? * 每天16:15触发
0 0 10,15,16 * * ? 每天10点,下午15点,16点触发
0 0/30 9-17 * * ? 9-17时内,每30分钟触发一次
0 0 12 ? * WED/0 0 12 ? * 4 每个星期三12点
0 15 10 * * ? 2005 2005年的每天10:15触发
0 * 14 * * ?” 每天14点到14:59期间的每1分钟触发
0 0/5 14 * * ? 每天14点到14:59期间的每5分钟触发
0 0/5 14,18 * * ? 每天14点到14:59期间和18点到18:55期间的每 5分钟触发
0 0-5 14 * * ? 每天14点到14:05期间的每1分钟触发
0 10,44 14 ? 3 WED 每年3月的星期三在14:10和14:44触发
0 15 10 ? * MON-FRI 周一至周五的10:15触发
0 15 10 15 * ? 每月15日10:15触发
0 15 10 L * ? 每月最后一日的10:15触发
0 15 10 ? * 6L 2002-2005 2002-2005年的每月的最后一个星期五10:15触发
0 15 10 ? * 6#3 每月的第三个星期五10:15触发

验证cron

  • 正则表达式方法
1
2
3
String regEx = "(((^([0-9]|[0-5][0-9])(\\,|\\-|\\/){1}([0-9]|[0-5][0-9]))|^([0-9]|[0-5][0-9])|^(\\* ))((([0-9]|[0-5][0-9])(\\,|\\-|\\/){1}([0-9]|[0-5][0-9]) )|([0-9]|[0-5][0-9]) |(\\* ))((([0-9]|[01][0-9]|2[0-3])(\\,|\\-|\\/){1}([0-9]|[01][0-9]|2[0-3]) )|([0-9]|[01][0-9]|2[0-3]) |(\\* ))((([0-9]|[0-2][0-9]|3[01])(\\,|\\-|\\/){1}([0-9]|[0-2][0-9]|3[01]) )|(([0-9]|[0-2][0-9]|3[01]) )|(\\? )|(\\* )|(([1-9]|[0-2][0-9]|3[01])L )|([1-7]W )|(LW )|([1-7]\\#[1-4] ))((([1-9]|0[1-9]|1[0-2])(\\,|\\-|\\/){1}([1-9]|0[1-9]|1[0-2]) )|([1-9]|0[1-9]|1[0-2]) |(\\* ))(([1-7](\\,|\\-|\\/){1}[1-7])|([1-7])|(\\?)|(\\*)|(([1-7]L)|([1-7]\\#[1-4]))))|(((^([0-9]|[0-5][0-9])(\\,|\\-|\\/){1}([0-9]|[0-5][0-9]) )|^([0-9]|[0-5][0-9]) |^(\\* ))((([0-9]|[0-5][0-9])(\\,|\\-|\\/){1}([0-9]|[0-5][0-9]) )|([0-9]|[0-5][0-9]) |(\\* ))((([0-9]|[01][0-9]|2[0-3])(\\,|\\-|\\/){1}([0-9]|[01][0-9]|2[0-3]) )|([0-9]|[01][0-9]|2[0-3]) |(\\* ))((([0-9]|[0-2][0-9]|3[01])(\\,|\\-|\\/){1}([0-9]|[0-2][0-9]|3[01]) )|(([0-9]|[0-2][0-9]|3[01]) )|(\\? )|(\\* )|(([1-9]|[0-2][0-9]|3[01])L )|([1-7]W )|(LW )|([1-7]\\#[1-4] ))((([1-9]|0[1-9]|1[0-2])(\\,|\\-|\\/){1}([1-9]|0[1-9]|1[0-2]) )|([1-9]|0[1-9]|1[0-2]) |(\\* ))(([1-7](\\,|\\-|\\/){1}[1-7] )|([1-7] )|(\\? )|(\\* )|(([1-7]L )|([1-7]\\#[1-4]) ))((19[789][0-9]|20[0-9][0-9])\\-(19[789][0-9]|20[0-9][0-9])))";
String tests = "0 0 0 L * ?";
System.out.println(tests.matches(regEx));
  • CronExpression验证
    这个方法需要引入quartz的jar包,然后只需要一行代码就可以验证了。
1
CronExpression.isValidExpression(cron)

Mac环境变量配置

mac一般使用bash作为默认shell,如果安装了oh my sh,则默认使用zshshell。

Mac系统环境变量的加载顺序:

/etc/profile
/etc/paths
~/.bash_profile
~/.bash_login
~/.profile
~/.bashrc

  • /etc/profile和/etc/paths是系统级别的,系统启动后就会加载。后面几个是当前用户级的环境变量。
  • 如果~/.bash_profile存在,后面几个文件就会忽略不读,不存在时,才会以此类推读取后面的文件。
  • ~/.bashrc没有上述规则,他始终加载,他是在bash shell打开的时候载入的。

设置Path的语法

1
2
# 中间使用冒号分隔
export PATH=$PATH:<PATH 1>:<PATH 2>:<PATH 3>:------:<PATH N>

全局设置

下面的几个文件设置是全局的,修改时需要root权限

  • /etc/paths (全局建议修改这个文件 )
    编辑 paths,将环境变量添加到 paths文件中 ,一行一个路径.
    /etc/paths 文件:

    1
    2
    3
    4
    /usr/bin
    /bin
    /usr/sbin
    /sbin
  • /etc/profile (建议不修改这个文件 )
    全局(公有)配置,不管是哪个用户,登录时都会读取该文件。

  • /etc/bashrc (一般在这个文件中添加系统级环境变量)
    全局(公有)配置,bash shell执行时,不管是何种方式,都会读取此文件。

单个用户设置

  • ~/.bash_profile (添加用户级环境变量)
    (注:Linux 里面是 .bashrc 而 Mac 是 .bash_profile)
    若bash shell是以login方式执行时,才会读取此文件,该文件仅仅执行一次,默认情况下,他设置一些环境变量。
    设置命令别名
    alias ll=’ls -la’
    设置环境变量:
    export PATH=/opt/local/bin:/opt/local/sbin:$PATH
    比如设置ANDROID_HOME到PATH:

    1
    2
    export ANDROID_HOME=/Users/shaoc/Library/Android/sdk
    export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH
  • ~/.bashrc 同上
    一般重启shell设置就会生效,如果想立刻生效,则可执行下面的语句:

    $ source 相应的文件

zsh中配置环境变量

在安装了oh my zsh后, .bash_profile 文件中的环境变量就无法起到作用,因为终端默认启动的是zsh,而不是bash shell,所以无法加载。

解决方法1:

在~/.zshrc配置文件中,增加对.bash_profile的引用:

`source ~/.bash_profile`

.bash_profile文件示例:

1
2
3
4
5
6
7
export ANDROID_HOME=/Users/pengdan/software/sdk
export NDK=/Users/pengdan/software/android-ndk-r10d
export GRADLE_HOME=/Users/pengdan/software/gradle-2.4
export SUBLIME=/Users/pengdan/home/subin
export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$GRADLE_HOME/bin:$PATH
export PATH=$PATH:$SUBLIME:/usr/local/mysql/bin
export PATH=$PATH:/Users/pengdan/software/apache-tomcat-7.0.70/bin

解决方法2:
可以使用zsh的方法进行配置:
(1)可以直接在~/.zshrc中添加path或者环境变量
(2)在目录~/oh-my-zsh/custom文件夹下的任何.zsh文件中的环境变量都将会加载。

.zshrc:

1
2
3
4
5
6
# Path to your oh-my-zsh installation.
export ZSH=/Users/shaoc/.oh-my-zsh
source $ZSH/oh-my-zsh.sh

alias zshconfig="vim ~/.zshrc"
source ~/.bash_profile

~/oh-my-zsh/custom/my.zsh:
alias subl=\''/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl'\'

系统为最新的macOS 11.2.3。

新安装第三方源软件报以下错误:”XX”已损坏,无法打开。 您应该将它移到废纸篓

检查安全性与隐私-任何来源

系统偏好设置 -> 安全性与隐私
检查该位置下”任何来源”是否已经存在
安全性与隐私
如果不包含”任何来源”,则打开终端,输入以下命令,然后输入电脑密码,回车
sudo spctl --master-disable

quarantine

重新打开之前报错软件,如果仍报错,继续以下操作
终端中输入以下命令(注意: 后面有个空格)
sudo xattr -d com.apple.quarantine /Applications/Alfred\ 4.app

然后重新打开应用即可,我的最多执行到此问题就解决了,如果还出现问题,则要排查一下是否是程序本身的问题。

名称 后盖型号 Internal Name
iPhone A1203 iPhone 1,1
iPhone 3G A1324 A1241 iPhone 1,2
iPhone 3GS A1325 A1303 iPhone 2,1
iPhone 4 A1349 A1332 iPhone 3,1 3,2 3,3
iPhone 4S A1431 A1387 iPhone 4,1
iPhone 5 A1428 A1429 A1442 iPhone 5,1 5,2
iPhone 5C A1456 A1507 A1516 A1529 A1532 iPhone 5,3 5,4
iPhone 5S A1453 A1457 A1518 A1528 A1530 A1533 iPhone 6,1 6,2
iPhone 6 A1549 A1586 A1589 iPhone 7,2
iPhone 6P A1522 A1524 A1593 iPhone 7,1
iPhone 6S A1633 A1688 A1700 iPhone 8,1
iPhone 6SP A1634 A1687 A1699 iPhone 8,2
iPhone SE A1723 A1662 A1724 iPhone 8,4
iPhone 7 A1660 A1778 A1779 iPhone 9,1 9,3
iPhone 7P A1661 A1784 A1785 iPhone 9,2 9,4
iPhone 8 A1863 A1905 A1906 iPhone 10,1 10,4
iPhone 8P A1864 A1897 A1898 iPhone 10,2 10,5
iPhone X A1865 A1901 A1902 iPhone 10,3 10.6
iPhone XR A1984 A2105 A2106 A2107 A2108 iPhone 11,8
iPhone XS A1920 A2097 A2098 A2099 A2100 iPhone 11,2
iPhone XS Max A1921 A2101 A2102 A2103 A2104 iPhone 11,6
iPhone 11 A2111 A2223 A2221 iPhone 12,1
iPhone 11 Pro A2160 A2217 A2215 iPhone 12,3
iPhone 11 Pro Max A2161 A2220 A2218 iPhone 12,5
iPhone SE 2 A2275 A2298 A2296 iPhone 12,8
iPhone 12 mini A2176 A2398 A2400 A2399 iPhone 13,1
iPhone 12 A2172 A2402 A2404 A2403 iPhone 13,2
iPhone 12 Pro A2341 A2406 A2408 A2407 iPhone 13,3
iPhone 12 Pro Max A2342 A2410 A2412 A2411 iPhone 13,4
iPhone 13 mini A2629 A2481 A2626 A2630 A2628 iPhone 14,4
iPhone 13 A2634 A2482 A2631 A2635 A2633 iPhone 14,5
iPhone 13 Pro A2639 A2483 A2636 A2640 A2638 iPhone 14,2
iPhone 13 Pro Max A2644 A2484 A2641 A2645 A2643 iPhone 14,3

mitmproxy github地址(Man-in-the-middle attack)

背景

Crash率是衡量一个App好坏的重要指标之一,如果你忽略了它的存在,它就会愈演愈烈
客户端的很大一部分的Crash是因为API返回的脏数据。比如当API返回空值、空数组或返回不是约定类型的数据,App收到这些数据,就极有可能发生空指针、数组越界和类型转换错误等Crash。而且这样的脏数据,特别容易引起线上大面积的崩溃。

异常数据测试方法

手工测试时,借助charles等抓包工具,对返回结果拦截修改数据,再进行数据的maplocal

异常数据修改规则

字符:非法字符、超长、null
数组:空数组、非法序列
接口超时:5s、10s
接口状态码:404、500、503
增加删除数据:数组、字典

mitmproxy是什么

顾名思义,mitmproxy 就是用于 MITM 的 proxy,MITM 即中间人攻击(Man-in-the-middle attack)。
mitmproxy
mitmproxy是一个支持HTTP和HTTPS的抓包程序,有类似Fiddler、Charles的功能,只不过它是一个控制台的形式操作。mitmproxy还有两个关联组件。一个是mitmdump,它是mitmproxy的命令行接口,利用它我们可以对接Python脚本,用Python实现监听后的处理。另一个是mitmweb,它是一个Web程序,通过它我们可以清楚观察mitmproxy捕获的请求。

mitmproxy有如下几项功能

  • 拦截HTTP和HTTPS请求和响应。
  • 保存HTTP会话并进行分析。
  • 模拟客户端发起请求,模拟服务端返回响应。
  • 利用反向代理将流量转发给指定的服务器。
  • 支持Mac和Linux上的透明代理。
  • 利用Python对HTTP请求和响应进行实时处理。

安装mitmproxy

brew install mitmproxy
安装完成后,系统将拥有 mitmproxy、mitmdump、mitmweb 三个命令
验证安装成功
mitmdump --version
应当可以看到类似于这样的输出:

1
2
3
4
Mitmproxy: 5.2
Python: 3.7.7
OpenSSL: OpenSSL 1.1.1g 21 Apr 2020
Platform: Darwin-19.6.0-x86_64-i386-64bit

运行

要启动 mitmproxy 用 mitmproxymitmdumpmitmweb 这三个命令中的任意一个即可,这三个命令功能一致,且都可以加载自定义脚本,唯一的区别是交互界面的不同。
mitmproxy 命令启动后,会提供一个命令行界面,用户可以实时看到发生的请求,并通过命令过滤请求,查看请求数据。形如:
启动 mitmproxy:
mitmweb
应当看到如下输出:

1
2
Web server listening at http://127.0.0.1:8081/
Proxy server listening at http://*:8080

设置代理+https证书安装

移动设备和电脑保存在一个wifi网络下,在移动设备在网络代理填写:电脑ip+8080(端口)
在浏览器输入:mitm.it,选择对应设备类型安装证书

脚本

完成了上述工作,我们已经具备了操作 mitmproxy 的基本能力 了。接下来开始开发自定义脚本,这才是 mitmproxy 真正强大的地方。
脚本的编写需要遵循 mitmproxy 规定的套路,这样的套路有两个,使用时选其中一个套路即可。
##第一个套路
编写一个 py 文件供 mitmproxy 加载,文件中定义了若干函数,这些函数实现了某些 mitmproxy 提供的事件,mitmproxy 会在某个事件发生时调用对应的函数,形如:

1
2
3
4
5
6
7
8
9
10
from mitmproxy import http
from mitmproxy import ctx

num = 0


def request(flow: http.HTTPFlow):
global num
num = num + 1
ctx.log.info("We've seen %d flows" % num)

第二个套路

编写一个 py 文件供 mitmproxy 加载,文件定义了变量 addons,addons 是个数组,每个元素是一个类实例,这些类有若干方法,这些方法实现了某些 mitmproxy 提供的事件,mitmproxy 会在某个事件发生时调用对应的方法。这些类,称为一个个 addon,比如一个叫 Counter 的 addon:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from mitmproxy import http
from mitmproxy import ctx


class Counter:
def __init__(self):
self.num = 0

def request(self, flow: http.HTTPFlow):
self.num = self.num + 1
ctx.log.info("We've seen %d flows" % self.num)


addons = [
Counter()
]

执行

这里强烈建议使用第二种套路,这也是官方内置的一些 addon 的实现方式。

我们将上面第二种套路的示例代码存为 addons.py,再重新启动 mitmproxy:

1
mitmweb -s addons.py

这个脚本是当 request 发生时,计数器加一,并打印日志。这里对应的是 request 事件

事件

事件针对不同生命周期分为 5 类:HTTP 生命周期、 TCP 生命周期、Websocket 生命周期、网络连接生命周期、通用生命周期

这里我们只介绍HTTP 生命周期的事件:
def http_connect(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 收到了来自客户端的 HTTP CONNECT 请求。在 flow 上设置非 2xx 响应将返回该响应并断开连接。CONNECT 不是常用的 HTTP 请求方法,目的是与服务器建立代理连接,仅是 client 与 proxy 的之间的交流,所以 CONNECT 请求不会触发 request、response 等其他常规的 HTTP 事件。

def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自客户端的 HTTP 请求的头部被成功读取。此时 flow 中的 request 的 body 是空的。

def request(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自客户端的 HTTP 请求被成功完整读取。

def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自服务端的 HTTP 响应的头部被成功读取。此时 flow 中的 response 的 body 是空的。

def response(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自服务端端的 HTTP 响应被成功完整读取。

def error(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 发生了一个 HTTP 错误。比如无效的服务端响应、连接断开等。注意与“有效的 HTTP 错误返回”不是一回事,后者是一个正确的服务端响应,只是 HTTP code 表示错误而已。

大多数情况下我们只会用到针对 HTTP 生命周期的几个事件。再精简一点,甚至只需要用到 http_connect、request、response 三个事件就能完成大多数需求了。

脚本示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
拦截请求的request
拦截返回的response
"""

from mitmproxy import http

def request(flow: http.HTTPFlow):
ctx.log.info("========================== intercept request start ==========================")
ctx.log.info("========================== host is:{} ========================== ".format(flow.request.host))
ctx.log.info("========================== url is:{} ========================== ".format(flow.request.url))
ctx.log.info("========================== method is:{} ========================== ".format(flow.request.method))
ctx.log.info("========================== intercept request end ==========================\n\n\n")

def response(flow: http.HTTPFlow):
code = flow.response.status_code

常用Api有

request

1
2
3
4
5
6
7
8
9
10
11
12
13
flow.request.headers # 获取所有头信息,包含Host、User-Agent、Content-type等字段
flow.request.url # 完整的请求地址,包含域名及请求参数,但是不包含放在body里面的请求参数
flow.request.pretty_url # 同flow.request.url目前没看出什么差别
flow.request.host # 域名
flow.request.method # 请求方式。POST、GET
flow.request.scheme # 什么请求 ,如https
flow.request.path # 请求的路径,url除域名之外的内容
flow.request.get_text() # 请求中body内容,有一些http会把请求参数放在body里面,那么可通过此方法获取,返回字典类型
flow.request.query # 返回MultiDictView类型的数据,url直接带的键值参数
flow.request.get_content() # bytes,结果如flow.request.get_text()
flow.request.raw_content # bytes,结果如flow.request.get_content()
flow.request.urlencoded_form # MultiDictView,content-type:application/x-www-form-urlencoded时的请求参数,不包含url直接带的键值参数
flow.request.multipart_form # MultiDictView,content-type:multipart/form-data时的请求参数,不包含url直接带的键值参数

response

1
2
3
4
flow.response.status_code #状态码
flow.response.text#返回内容,已解码
flow.response.content #返回内容,二进制
flow.response.setText()#修改返回内容,不需要转码

设计流程

在上面提到可以拦截request和response,那么就可以对response数据做修改,再返回修改后的数据.
基于上面提到修改数据规则,随机多拦截数据做随机修改.
保存修改前和修改后的数据,方便数据diff.
设计流程

用于检查测试中得到的响应数据等是否符合预期,用以保证性能测试过程中的数据交互与预期一致。

使用断言的方法:

△在选择的Sampler下添加对应的断言(因为不同类型的断言检查的内容不同);配置好响应的检查内容(根据断言情况而定,有的断言控制面板不需要添加任何内容,如XML Assertion)。
△添加一个断言结果的监听器(从监听器中添加),通过“断言结果”可以看到是否通过断言;对于一次请求,如果通过的话,断言结果中只会打印一行请求的名称;
如果失败,则除了请求的名称外,还会有一行失败的原因(不同类型的断言,结果不同)。

PS:一个Sampler可以添加多个断言,根据你的检查需求来添加相应的断言,当Sampler下所有的断言都通过了,那么才算request成功。

响应断言

判断返回内容中的内容
作用对象:响应报文中的所有对象
响应断言
APPly to:适用范围
Main sample and sub-samples:作用于父节点取样器及对应子节点取样器
Main sample only:仅作用于父节点取样器
Sub-samples only:仅作用于子节点取样器
JMeter Variable:作用于jmeter变量(输入框内可输入jmeter的变量名称)

要测试的响应字段:要检查的项
* 响应文本:服务器响应文本,一般情况下,我们都是勾选改选项,用于验证服务器返回值。
* 响应代码:即http响应代码,例如200,404等等,需要注意: 由于jmeter默认情况下认为4xx,5xx时该请求失败,所以在断言这类响应代码时,需要同时勾选Ingore Status,才能正常去做断言。
* 响应信息:即响应代码对应的信息,例如OK, Not Found等等这类的。
* Response Headers:响应头部
* 求情头
* URL样本
* Documeng(text):测试文件
* Ignore status:忽略返回的响应报文状态码
* 请求数据

模式匹配规则:
* 包括:返回结果包括你指定的内容
* 匹配:(好像跟Equals查不多,弄不明白有什么区别)
* Equals:返回结果与你指定结果一致
* Substring:返回结果是指定结果的字串
* 否:不进行匹配
* 或者

要测试的模式:即填写你指定的结果(可填写多个),按钮【添加】、【删除】是进行指定内容的管理

断言持续时

前言

在默认情况下,jmeter 发送每个请求之间是没有延时的,如果采用默认方式,如果线程数足够大,瞬间就会将服务器压死。再则在实际的业务过程中,请求之间是有一定时间的停顿的所以在请求之间设置合理的延时是必须的,也是更接近用户真实业务情况。在 jmeter 中,定时器组件提供了系列不同类型的延时控制。合理使用定时器组件,能让你的性能测试更接近真实,更能挖掘出系统的瓶颈和评估系统的性能指标。

定时器类型

定时器类型

1、固定定时器(Constant Timer)

这是最简单的一种定时器,也是新手最常用的一种方式。下面我们看下其具体设置:
固定定时器
作用:通过ThreadDelay设定每个线程请求之前的等待时间(单位为毫秒)。注意:固定定时是有作用域的,放到线程组下其作用域是所有请求都会延迟固定器设置的时间,如果放到请求内,作用域是单个请求延迟时间(常用)。

2、高斯随机定时器(Gaussian Random Timer)

高斯随机定时器,又可以称作正态分布随机定时器,该定时器可以设置在两个请求间随机延时时长。且总的延时是高斯分布(正态分布)的总和(均值:0.0、标准差 1.0)。在使用时须指定偏差延时值和偏移值。。下面我们看下其具体设置:
高斯随机定时器

例如在访问百度首页,然后输入关键词进行搜索,受网络、人等各种因素影响,有的人打开首页后 3s 后则进行了搜索,有时则是 10s或更多时间,在正常情况下,打开百度然后进行搜索,假设用户间隔在 3s-10s 之间,从统计学来看,这个间隔时间可能是一个正态分布或接近正态分布。而不是一个固定的常量。从笔者在日常实践中,也更推荐使用该定时器。能更接近模拟用户实际情况。

3、同步定时器(Synchronizing Timer)

同步定时器

用来设置集合点,其作用是:阻塞线程,直到指定的线程数量到达后,再一起释放,可以瞬间产生很大的压力
(1)Number of Simulated Users to Group by:模拟用户的数量,即指定同时释放的线程数数量,若设置为0,等于设置为线程组中的线程数量;
(2)Timeout in milliseconds:超时时间,即超时多少毫秒后同时释放指定的线程数;如果设置为0,该定时器将会等待线程数达到了设置的线程数才释放,

若没有达到设置的线程数会一直死等。如果大于0,那么如果超过Timeout inmilliseconds中设置的最大等待时间后还没达到设置的线程数,Timer将不再等待,释放已到达的线程。默认为0
同步定时器(Synchronizing Timer)的超时时间设置要求:超时时间 > 请求集合数量 * 1000 / (线程数 / 线程加载时间)

场景应用:0点秒杀

4、统一随机定时器(Uniform Random Timer)

该定时器可以在请求之间设置一个随机延时,每个随机延时有相同的发生概率。
总延迟时间=指定范围内的随机时间+固定延迟时间
统一随机定时器

5、泊松随机定时器(Poisson Random Timer)

类似高斯随机定时器,只是其随机延时值发生在一个特定的值。总的延时值呈现泊松分布。
泊松随机定时器

作用:这个定时器在每个线程请求之前按随机的时间停顿,总的延迟就是泊松分布值和偏移值之和。
上面表示暂停时间会分布在100到400毫秒之间:
(1)Lambda(in milliseconds):兰布达值
(2)Constant Delay Offset(in milliseconds):暂停的毫秒数减去随机延迟的毫秒数

6、常数吞吐量定时器(Constant Throughput Timer)

通过控制每分钟请求数(即控制吞吐的方式)来控制是否进行延时暂停。
例如,当我们需要使服务端长期处于一定的压力下时,可以通过该定时器来控制吞吐。
注意:吞吐值可以是常量,也可以使用函数来动态生成,已达成更灵活的使用,满足不同的压力场景。
常数吞吐量定时器

作用: 按指定的吞吐量执行,以每分钟为单位。计算吞吐量依据是最后一次线程的执行时延。

Target throughput(in samples per minute):目标吞吐量。注意这里是每分钟发送的请求数,可以选择作用的线程:当前线程、当前线程组、所有线程组等,具体含义如下:
**this thread only: *设置每个线程的吞吐量。总的吞吐量=线程数该值。
all active threads in current thread group:吞吐量被分摊到当前线程组所有的活动线程上。每个线程将根据上次运行时间延迟。
all active threads:吞吐量被分配到所有线程组的所有活动线程的总吞吐量。每个线程将根据上次运行时间延迟。在这种情况下,每个线程组需要一个具有相同设置的固定吞吐量定时器。(不常用)
all active threads in current thread group (shared):同上,但是每个线程是根据组中的线程的上一次运行时间来延迟。相当于线程组组内排队。(不常用)
all active threads (shared):同上,但每个线程是根据线程的上次运行时间来延迟。相当于让所有线程组整体排队。(不常用)

7、准确的吞吐量定时器(Precise Throughput Timer)

准确的吞吐量定时器

Target Throught:目标吞吐量
Throught Period:表示在多长时间内发送Target Throught指定的请求数(以秒为单位)
Test Druation:指定测试运行时间(以秒为单位)
Number of threads in the bath:用来设置集合点,等到指定个数的请求后并发执行其它参数默认即可

8、JSr R223 Timer 和 BeanShell Timer

这两种定时器就不细说了,简单的说就是提供了脚本方式来进行控制,是更为灵活的方式。一般情况下,大家是不会用的。当然有兴趣的,可以去研究下,增强理解。

总结
本文就各种定时器进行了介绍,并大致介绍了其可能的应用场景。不管是哪种定时器,都需要深入理解业务的情况下,统筹规划使用。以更深入的发挥其作用,模拟好真实应用场景,更好的挖掘性能瓶颈和评估目标服务的性能情况。

官方文档

常用

__BeanShell

  • 入参:BeanShell语法的程序语句或者Bean Shell脚本文件

  • 示例:

    1
    2
    ${__BeanShell(123*456,)}:返回56088;
    ${__BeanShell(source("function.bsh",))}:执行在function.bsh中的脚本;

    BeanShell

__Random

  • 作用:生成指定范围内的随机数
  • 入参:左右范围;变量名
  • 示例:
1
${__Random(1,20,random_num)}

__Random

__RandomDate

  • 作用:生成指定范围内的日期
  • 入参:日期格式;左右范围;语言;变量名
  • 示例:
1
${__RandomDate(,,2050-07-08,,)}

__RandomDate

__RandomFromMultipleVars

首先要创建用户定义的变量name1,name2,areaCode

  • 作用:在设定的几个值中随机使用其一,如下在name1、nema2、areaCode中随机使用
  • 入参:多个值,使用|分隔;变量名
  • 示例:
1
${__RandomFromMultipleVars(name1|name2|areaCode,name)}

__RandomFromMultipleVars

__RandomString

  • 作用:生成指定长度的字符串
  • 入参:字符串长度;可选字符串;变量名
  • 示例:
1
${__RandomString(2,我爱你祖国,random_char)}

__RandomString

__UUID

  • 作用:获取UUID
  • 入参:无
  • 示例:
1
${__UUID}

__UUID

__time

  • 作用:返回当前时间,可指定返回格式,由SimpleDateFormat类处理函数格式
    • 年:yyyy
    • 月:MM
    • 日:dd
    • 时:hh
    • 分:mm
    • 秒:ss
  • 入参:返回格式;变量名
  • 示例:
1
${__time(yyyy-MM-dd hh:mm:ss,)}

__time

__timeShift

  • 作用:
  • 入参:
    • 格式:创建日期的格式。如果该值未被传递,则以毫秒为单位创建日期。
    • 日期:日期值
    • 移位:从日期参数的值中添加或减去多少天,几小时或几分钟
      • “PT20.345S”解析为“20.345秒”
      • “PT15M”解析为“15分钟”
      • “PT10H”解析为“10小时”
      • “P2D”解析为“2天”
      • “P2DT3H4M”解析为“2天,3小时和4分钟”
      • “P-6H3M”解析为“-6小时+3分钟”
      • “-P6H3M”解析为“-6小时-3分钟”
      • “-P-6H + 3M”解析为“+6小时和-3分钟”
    • 区域设置:设置创建日期的显示语言
    • 变量名
  • 示例:
1
${__timeShift(yyyy-MM-dd HH:mm:ss,,P2D,,c)}

__timeShift

##__counter

  • 作用:作为一个计数器使用,支持多线程(多用户)
  • 入参:计数变量i,是否为线程计数器True/False
  • 示例
1
2
${__counter(FALSE,count)}; 全局计数器
${__counter(TRUE,count)}; 每个用户有自己的计数器

__counter

__intSum

  • 作用:整数求和,多个数字之间用逗号分隔
  • 入参:第一个整数;第二个及之后的整数;变量名
  • 示例:
1
${__intSum(1,2,test)}

__intSum

__longSum

  • 作用:计算长整型的和
  • 入参:整数
  • 示例
1
${__longSum(1,2],sum)}

__longSum

__CSVRead

  • 作用:从文件读取指定列的值(读取固定值/读取动态值/使用文件别名)
  • 入参:文件路径;读取方式;
  • 示例
1
2
3
4
5
${__CSVRead(/Users/vic/Downloads/Jmeter ALY/phone_numbers.csv,0)};读取第一列的值
${__CSVRead(/Users/vic/Downloads/Jmeter ALY/phone_numbers.csv,next())}; 每次读取下一次的值,配合第一条使用,否则不知道从哪里开始

${__CSVRead(/Users/vic/Downloads/Jmeter ALY/phone_numbers.csv,*user_info)};使用别名,然后通过以下方法获取数据
${__CSVRead(*user_info, 1)}

__CSVRead

其他

应用场景:

在一个线程组中,从前一个请求的响应结果中,提取到某些需要的内容,可以作为下一个接口需要的入参从而实现关联
添加路径:HTTP请求->添加->后置处理器->正则表达式提取器
添加正则表达式提取器

说明

下面是JMeter-正则表达式提取器的界面
正则表达式提取器

  • 后置处理器:在请求结束或者返回响应结果时发挥作用

  • 正则表达式提取器:允许用户从服务器的响应中通过使用perl的正则表达式提取值。该元素会作用在指定范围取样器,用正则表达式提取所需值,生成模板字符串,并将结果存储到给定的变量名中。

  • **APPly to:**作用范围(返回内容的断言范围)

    • Main sample and sub-samples:作用于父节点的取样器及对应子节点的取样器
    • Main sample only:仅作用于父节点的取样器
    • Sub-samples only:仅作用于子节点的取样器
    • JMeter Variable:作用于jmeter变量(输入框内可输入jmeter的变量名称)
  • 要检查的响应字段:需要检查的响应报文的范围

    • 主体:Response Body,响应数据主体
    • Body(unescaped): 主体,响应的主体内容且替换了所有的html转义符,注意html转义符处理时不考虑上下文,因此可能有不正确的转换,不太建议使用
    • Body as a Document:从不同类型的文件中提取文本,注意这个选项比较影响性能
    • Response Headers:响应信息头
    • Request Headers: 请求信息头
    • URL:统一资源定位符,即Internet上用来描述信息资源的字符串
    • Response Code: 响应状态码,比如:200、404等
    • Response Message: 响应信息,比如:OK
  • 引用名称(Reference Name):Jmeter变量的名称,存储提取的结果;即下个请求需要引用的值、字段、变量名(例子中我提取的是SOCIAL_NO)

  • 引用方法:${xxx}

  • 正则表达式(Regular Expression):使用正则表达式解析响应结果,“()”表示提取字符串中的部分值
    正则表达式

  • 模板(Template): 用$$引用起来,如果在正则表达式字段中,文本框写了多个正则表达式,则可以是$2$$3$等等,表示提取到的第几个值给引用名称。如:$1$表示匹配到的第1个值赋给引用名称。

  • 匹配数字(Match No):正则表达式匹配数据的结果可以看做一个数组,表示如何取值:0代表随机取值,正数n则表示取第n个值(比如1代表取第一个值),负数则表示提取所有符合条件的值。

  • 缺省值:匹配失败时候的默认值;通常用于后续的逻辑判断,一般通常为特定含义的英文大写组合,比如:ERROR

正则表达式的举例说明:

1、提取单个字符串:

假设我们想要匹配Web页面的如下部分:name = “file” value = “readme.txt”>并要提取readme.txt。一个合适的正则表达式是:name = “file” value = “(.+?)”>。我们可以这么写:

引用名称:file
正则表达式:name = “file” value = “(.+?)”>
模板:$1$
readme.txt在需要引用的地方可以通过:${file}进行使用。

2、提取多个字符串:

假设我们想要匹配Web页面的如下部分:name = “file.name” value = “readme.txt”>并要提取file.name和readme.txt。一个合适的正则表达式是:name = “(.+?)” value = “(.+?)”。这样就会创建2个组,分别用于$1$和$2$。我们可以这么写:

引用名称:file
正则表达式:name = “(.+?)” value = “(.+?)”
模板:$1$$2$
如下变量的值将会被设定为:
file : file.namereadme.txt
file_g0 : name = “file.name” value = “readme.txt”
file_g1 : file.name
file_g2 : readme.txt

在需要引用的地方可以通过:${file}, ${file_g0},{file_g1},{file_g2}进行使用。

3、正则表达式中有转义符(例如: \ ?),需要进行转义:

例如:id?test":”1234” ,我们想要匹配出1234。

一个合适的正则表达式是: id?test\“:”(.+?)”

4、从消息头(header)提取token:

正则表达式提取器

一、JMeter参数化简介

JMeter参数化的概念

当使用JMeter进行测试时,测试数据的准备是一项重要的工作。若要求每次迭代的数据不一样时,则需进行参数化,然后从参数化的文件中来读取测试数据。

参数化:是自动化测试脚本的一种常用技巧,可将脚本中的某些输入使用参数来代替,如登录时利用GET/POST请求方式传递参数的场景,在脚本运行时指定参数的取值范围和规则。
脚本在运行时,根据需要选取不同的参数值作为输入,该方式称为数据驱动测试(Data Driven Test),而参数的取值范围被称为数据池(Data Pool)。

JMeter参数化方式之使用场景对比

参数化方式 使用场景
1 User Parameters 适用于参数取值范围很小的时候使用
2 CSV Data Set Config 适用于参数取值范围较大的时候使用,该方法具有更大的灵活性
3 User Defined Variables 一般用于Test Plan中不需要随请求迭代的参数设置,如:Host、Port Number
4 函数助手:_CSVRead 可作为其他参数化方式的补充项,如:随机数生成的函数${__Random(,,)}

二、JMeter参数化的4种主要方式-操作演练

User Parameters(用户参数)

操作路径:HTTP请求–>添加–>前置处理器–>用户参数
1)添加User Parameters功能模块
添加用户参数
2)设置参数项、参数值
用户参数
3)配置HTTP取样器界面的请求参数:${xxx}
HTTP请求参数配置
4)配置Thread Group
设置线程数=2,即2个虚拟用户数,对应User Parameters中设置的2个用户
线程数

CSV Data Set Config(CSV数据配置)

操作路径:线程组–>添加–>配置元件–>CSV Data Set Config
1)添加CSV Data Set Config模块
添加CSV数据配置
2)预先准备好要参数化的所有参数值(txt、csv文件)
参数文件
3)配置CSV Data来源
CSV数据配置
4)设置HTTP取样器的请求参数:${xxx}
HTTP请求参数配置

User Defined Variables(用户自定义变量)

操作路径:线程组–>添加–>配置元件–>用户自定义变量
1)添加User Defined Variables模块
添加用户自定义变量
2)配置User Defined Variables界面中的参数及其值
用户自定义变量
3)配置HTTP取样器中的请求参数
HTTP请求参数配置

函数助手

操作路径:Tools–>函数助手对话框
1)选择参数化所需的函数,配置函数
打开函数对话助手
配置函数
2)配置HTTP取样器的请求参数
HTTP请求参数配置

JMeter可以通过鼠标拖拽来随意改变元件之间的顺序以及元件的父子关系,那么随着它们的顺序和所在的域不同,它们在执行的时候,也会有很多不同。

JMeter的test plan通过图形化的方式表达脚本,域代码方式的脚本不同,图形方式表达的脚本中无法使用变量和函数等描述元件的作用域,因此jmeter主要依靠test plan中元件的相对位置、父子关系以及元件本身的类型来决定test plan中各元件的执行顺序;原件在test plan中的位置不同,可能导致该元件的行为有很大差异。

元件的作用域

jmeter中共有8类可被执行的元件(test plan和thread group不属于元件),其中,sampler(取样器)是不与其他元件发生交互的作用的元件,Logic Controller(逻辑控制器)只对其子节点的sampler有效,而其他元件需要与sampler等元件交互。

  • Config Elements(配置元件):影响其范围内的所有元件
  • Pre-porcessors(前置处理器):在其作用范围内的每一个sampler元件之前执行
  • Timer(定时器):对其作用范围内的每一个sampler有效
  • Post-porcessors(后置处理器):在其作用范围内的每一个sampler元件之后执行
  • Assirtions(断言):对其作用范围内的每一个sampler元件执行后的结果执行校验
  • Listener(监听器):收集其作用范围内的每一个sampler元件的信息并且呈现出来

在jmeter中,元件的作用域是靠test plan的树形结构中元件的父子关系来确定的,其原则如下:

  • sampler不与其他元件相互作用,因此不存在作用域问题
  • Logic Controller只对其子节点中的sampler和Logic Controller作用
  • 除sampler和Logic Controller外的其他元件,如果是某个sampler的子节点,则该元件仅对其父节点作用
  • 除sampler和Logic Controller外的其他元件,如果其父节点不是sampler,则其作用域是该元件父节点下的其他所有后带节点(包括子节点,子节点的子节点等)

元件的执行顺序

在同一作用域范围内,test plan中的元件按照以下顺序执行:

  • Config Elements(配置元件)

  • Pre-porcessors(前置处理器)

  • Timer(定时器)

  • Sampler(取样器)

  • Post-porcessors(后置处理器)(除非Sampler得到的返回结果为空)

  • Assirtions(断言)(除非Sampler得到的返回结果为空)

  • Listener(监听器)(除非Sampler得到的返回结果为空)

    注意:Pre-porcessors、Post-porcessors和Assirtions等元件仅对Sampler作用,如在它们作用域内没有任何Sampler,则不会被执行;
    如果在同一作用域范围内有多个同一类型的元件,则这些元件按照它们在test plan中的上下顺序依次执行。

启动JMeter——>测试计划——>添加线程组

配置元件→添加http信息头管理器

  • HTTP Header Manager(信息头管理器)
    用于定制Sampler发出的HTTP请求的请求头的内容。

  • HTTP Request Defaults(请求默认值)
    用于设置其作用范围内的所有HTTP的默认值,可被设置的内容包括HTTP请求的host、端口、协议等

  • HTTP Cache Manager(缓存管理器)
    用于模拟浏览器的Cache行为。为Test Plan增加该属性管理器后,Test Plan运行过程中会使用Last-Modified、ETag和Expired等决定是否从Cache中获取相应的元素

  • HTTP Cookie Manager(Cookie管理器)
    用于管理Test Plan运行时的所有Cookie。HTTP Cookie Manager可以自动储存服务器发送给客户端的所有Cookie,并在发送请求时附加上合适的Cookie

HTTP信息头管理器添加好之后,需要填入信息头的名称以及对应的值,如下
HTTP信息头管理器

Sampler(取样器)→HTTP请求

HTTP请求
填入测试的服务器地址、端口、所用的户协议、方法,这里方法我用的是POST,然后填入路径,选择Body Data

关于http请求的的属性参数说明:

  • 名称:用于标识一个sample。建议使用一个有意义的名称
  • 注释:对于测试没任何影响,仅用来记录用户可读的注释信息
  • 协议:向目标服务器发送http请求时的协议,http/https,大小写不敏感,默认http
  • 服务器名称或IP:http请求发送的目标服务器名称或者IP地址,比如:www.baidu.com
  • 端口号:目标服务器的端口号,默认值为443,可不填
  • 方法:发送http请求的方法,比如POST
  • 路径:目标的URL路径(不包括服务器地址和端口)
  • Content encoding:内容的编码方式(Content-Type=application/json;charset=utf-8)
  • 自动重定向:如果选中该项,发出的http请求得到响应是301/302,jmeter会重定向到新的界面
  • Use keep Alive:jmeter 和目标服务器之间使用 Keep-Alive方式进行HTTP通信(默认选中)
  • Use multipart/from-data for HTTP POST :当发送HTTP POST 请求时,使用
  • Parameters、Body Data以及Files Upload的区别:
    1. parameter是指函数定义中参数,而argument指的是函数调用时的实际参数
    2. 简略描述为:parameter=形参(formal parameter), argument=实参(actual parameter)
    3. 在不很严格的情况下,现在二者可以混用,一般用argument,而parameter则比较少用
    4. Body Data指的是实体数据,就是请求报文里面主体实体的内容,一般我们向服务器发送请求,携带的实体主体参数,可以写入这里
    5. Files Upload指的是:从HTML文件获取所有有内含的资源:被选中时,发出HTTP请求并获得响应的HTML文件内容后还对该HTML
      进行Parse 并获取HTML中包含的所有资源(图片、flash等):(默认不选中)
      如果用户只希望获取特定资源,可以在下方的Embedded URLs must match 文本框中填入需要下载的特定资源表达式,只有能匹配指定正则表达式的URL指向资源会被下载

监听器 →察看结果树

添加好监视器,点击运行,开始测试
测试结束后,如果我们的请求成功,那么结果树里面的模拟请求会显示为绿色,可以通过取样器结果里面的响应状态码信息来判断
结果树

也可以点击请求模块,查看我们发送的请求
里面有我们发送的请求的方法、协议、地址以及实体主体数据,以及数据类型,大小,发送时间等信息
请求数据

响应数据:里面包含服务器返回给我们的响应数据实体,如下图
响应数据

一、添加录制控制器

启动jmeter:在测试计划中添加线程组,线程组中添加逻辑控制器→录制控制器

二、添加HTTP代理服务器

工作台:添加非测试元件→HTTP代理服务器

三、配置代理服务器

服务器的配置,可以根据下面的代理服务器详细说明,根据需要配置不同代理模式。
HTTP代理服务器

代理服务器说明

1)名称:代理服务器名称,可以自定义
2)注释:对此代理服务器的说明,可自定义,默认为空
3)Global Settings

1
2
端口:JMeter代理服务器端口,需要检查端口是否被占用
HTTPS Domains:https协议要监听的域名,如访问:https://api.xiaoyuzhoufm.com/

4)Test plan content

1
2
3
目标控制器:下拉选项,表明在哪个模块下面保存录制的请求
分组:下拉框;对录制的请求按照一定方式进行进行分组,一般默认使用【不对样本分组】即可
记录http信息头、添加断言、Regex matching:勾选框;记录每个请求的request header、断言、正则表达式匹配等,录制一般使用默认勾选就行

5)HTTP Sampler settings

1
2
3
4
5
6
A)Type:http采样器的type类型,默认为空
 B)Prefix:对每个录制的http请求的前缀命名,默认为空,则录制的请求会按照数字递增的方式进行命名,如:012......
C)自动重定向:勾选框;表示请求是否自动重定向
D)跟随重定向:勾选框;表示请求是否跟随重定向
E)User KeepAlive:勾选框;表示此http请求的TCP链接是否保持不中断
F)从HTML文件获取所有内涵的资源:勾选框,表示是否获取html文件中的资源信息,录制时一般默认不勾选

6)Content-Type filter

1
2
A)Include:Content-Type的白名单,表示那些Content-Type可以通过
B)Exclude:Content-Type黑名单,表示那些Content-Type被拒绝

7)包含模式:表示哪些请求信息会被录制,如:*.html
8)排除模式:表示那些请求信息不会被录制,可点击Add suggested Excludes使用默认排除方式,
包含模式&排除模式 就是我们需要的和我们不需要的。一般情况下,我们只需要排除我们不需要的。
格式:

1
2
3
4
5
 .*\.css 排除css文件," .* " 匹配任意字符的意思 " \ "是转义的意思

 .*\.js 排除js文件

.*\.png 排除png文件

9)Notify Child Listeners of filtered samplers:是否唤起过滤取样器的后台监听,默认勾选即可

四、本地设置代理

浏览器或手机设置为电脑代理

五、SSL问题

如果在录制过程中提示:SSL问题 ,那就需要安装SSL安全证书。
SSL
1)生成证书,在点击HTTP代理服务器的“启动”按钮后,弹出提示框:提示我们,CA证书已经创建,在jmeter的bin目录下
2)安装证书(jmeter) 选择菜单栏“选项—SSL管理器”,再打开的对话框中选择bin目录下的证书
3)手机需要安装apache-jmeter-5.1.1/bin目录下ApacheJMeterTemporaryRootCA.crt证书

六、脚本录制

代理服务器配置后之后,点击启动,代理服务器就会开始记录所接受的http请求

测试计划(test plan)

描述一个性能测试,包含本次测试所有相关功能
测试计划

threads(users)线程

线程组
Setup thread group:
一种特殊类型的线程,可用于执行预测试操作。即执行测试前进行定期线程组的执行

Teardown thread group:
一种特殊类型的线程,可用于执行测试后动作。即执行测试结束后执行定期的线程组

Thread group:
通常添加使用的线程,一般一个线程组可看做一个虚拟用户组,其中每个线程为一个虚拟用户

测试片段(test fragment)

应用在控制器上的一个特殊线程组,与线程组处于同一层级,必须与Include Controller或模块控制器一起使用才被执行。
应用场景:
1、当jmeter脚本非常复杂的时候,可以通过测试片段分模块管理用例
2、当jmeter脚本由多个测试人员共同完成,通过测试片段分人分模块管理用例

取样器(Sampler)

取样器
是性能测试中向服务器发送请求,记录响应信息,记录响应时间的最小单元,JMeter 原生支持多种不同的sampler
如 HTTP Request Sampler 、 FTP Request Sampler 、TCP Request Sampler 、JDBC Request Sampler 等
每一种不同类型的 sampler 可以根据设置的参数向服务器发出不同类型的请求。
Java Request Sampler 和 Beanshell Request Sampler 是两种特殊的可定制的 Sampler (暂不讨论)

逻辑控制器(Logic Controller)

逻辑控制器
包含两类原件:
一类是控制Test Plan中Sampler节点发送请求的逻辑顺序控制器,常用的有:If Controller、Swith Controller、Loop Controller、Random Controller等
另一类是用来组织和控制Sampler节点的,如Transaction Controller、Throughput Controller等

监听器(Listener)

监听器
对测试结果进行处理和可视化展示的一系列组件,常用的有图形结果、查看结果树、聚合报告等
以上的五类原件就可以构成一个简单的性能测试脚本

聚合报告
Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值
Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100
Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间
Median:中位数,也就是 50% 用户的响应时间
90% Line:90% 用户的响应时间
Min:最小响应时间
Max:最大响应时间
Error%:本次测试中出现错误的请求的数量/请求的总数
Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数
KB/Sec:每秒从服务器端接收到的数据量

配置元件(Config Element)

配置元件
用于提供对静态数据配置的支持。CSV Date Set Config可以将本地数据文件形成数据池(Date Pool),而对应于HTTP Request Configuration和TCP Request Sample等类型的Configuration元件则可以修改这些Sample的默认数据等

定时器(Time)

定时器
用于操作之间设置等待时间,等待时间使性能测试中常用的控制客户端QPS的手段,jmeter定义了Constant Times、

Constant Throughput Times、Guass Ramdon Times等不同类型的Times

断言(Assertions)

断言
用于检查测试中得到的响应数据等是否符合预期,Assertions一般用来设置检查点,用以保证性能测试过程中的数据交互与预期一致

前置处理器(Pre Processors)

前置处理器
用于在实际请求发出之前对即将发出的请求进行特殊处理。
例如:当URL中有sessionID一类的session信息时,可以通过该处理器填充发出请求实际的sessionID。

后置处理器(Pre Processors)

后置处理器
用于对Sampler发出请求后得到的服务器响应进行处理。一般用来提取响应中的特定数据
例如:正则表达式,用于提取响应数据中匹配某正则表达式的数据段,

JMeter官网下载
Jmeter版本

运行方法一,直接运行

解压后
命令行进入/Users/vic/apache-jmeter-5.1.1/bin目录下,输入sh jmeter即可启动

运行方法二,配置环境变量

配置环境变量
vim ~/.bash_profile

内容输入举例:

1
2
export JMETER_HOME=/Users/vic/apache-jmeter-5.1.1
export PATH=$PATH:$JMETER_HOME/bin

使环境变量生效
source ~/.bash_profile

修改jmeter为中文:
编辑/Users/vic/apache-jmeter-5.1.1/bin目录下的jmeter.properties文件
修改第37行左右如下:
Jmeter版本

打开终端输入:jmeter 启动JMeter