安装
C:\Users\lifeng01>pip?install?locust
Collecting?locust
??Downloading?locust-2.5.0-py3-none-any.whl?(795?kB)
?????|████████████████████████████████|?795?kB?364?kB/s
Requirement?already?satisfied:?msgpack>=0.6.2?in?d:\python\python37\lib\site-packages?(from?locust)?(1.0.2)
Requirement?already?satisfied:?ConfigArgParse>=1.0?in?d:\python\python37\lib\site-packages?(from?locust)?(1.4)
Collecting?geventhttpclient>=1.5.1
??Downloading?geventhttpclient-1.5.3-cp37-cp37m-win_amd64.whl?(36?kB)
Requirement?already?satisfied:?requests>=2.9.1?in?d:\python\python37\lib\site-packages?(from?locust)?(2.25.0)
Collecting?pyzmq>=22.2.1
??Downloading?pyzmq-22.3.0-cp37-cp37m-win_amd64.whl?(1.1?MB)
?????|████████████████████████████████|?1.1?MB?252?kB/s
Collecting?Flask-Cors>=3.0.10
??Downloading?Flask_Cors-3.0.10-py2.py3-none-any.whl?(14?kB)
Requirement?already?satisfied:?psutil>=5.6.7?in?d:\python\python37\lib\site-packages?(from?locust)?(5.8.0)
Requirement?already?satisfied:?typing-extensions>=3.7.4.3?in?d:\python\python37\lib\site-packages?(from?locust)?(3.7.4.3)
Collecting?Werkzeug>=2.0.0
??Downloading?Werkzeug-2.0.2-py3-none-any.whl?(288?kB)
?????|████████████████████████████████|?288?kB?192?kB/s
Requirement?already?satisfied:?Flask-BasicAuth>=0.2.0?in?d:\python\python37\lib\site-packages?(from?locust)?(0.2.0)
Requirement?already?satisfied:?pywin32?in?d:\python\python37\lib\site-packages?(from?locust)?(228)
Collecting?flask>=2.0.0
??Downloading?Flask-2.0.2-py3-none-any.whl?(95?kB)
?????|████████████████████████████████|?95?kB?270?kB/s
Collecting?roundrobin>=0.0.2
??Downloading?roundrobin-0.0.2.tar.gz?(2.4?kB)
??Preparing?metadata?(setup.py)?...?done
Requirement?already?satisfied:?gevent>=20.9.0?in?d:\python\python37\lib\site-packages?(from?locust)?(21.1.2)
Collecting?Jinja2>=3.0
??Downloading?Jinja2-3.0.3-py3-none-any.whl?(133?kB)
?????|████████████████████████████████|?133?kB?252?kB/s
Requirement?already?satisfied:?click>=7.1.2?in?d:\python\python37\lib\site-packages?(from?flask>=2.0.0->locust)?(7.1.2)
Collecting?itsdangerous>=2.0
??Using?cached?itsdangerous-2.0.1-py3-none-any.whl?(18?kB)
Requirement?already?satisfied:?Six?in?d:\python\python37\lib\site-packages?(from?Flask-Cors>=3.0.10->locust)?(1.12.0)
Requirement?already?satisfied:?zope.interface?in?d:\python\python37\lib\site-packages?(from?gevent>=20.9.0->locust)?(5.3.0)
Requirement?already?satisfied:?zope.event?in?d:\python\python37\lib\site-packages?(from?gevent>=20.9.0->locust)?(4.5.0)
Requirement?already?satisfied:?setuptools?in?d:\python\python37\lib\site-packages?(from?gevent>=20.9.0->locust)?(41.2.0)
Requirement?already?satisfied:?cffi>=1.12.2?in?d:\python\python37\lib\site-packages?(from?gevent>=20.9.0->locust)?(1.14.5)
Requirement?already?satisfied:?greenlet<2.0,>=0.4.17?in?d:\python\python37\lib\site-packages?(from?gevent>=20.9.0->locust)?(1.0.0)
Requirement?already?satisfied:?certifi?in?d:\python\python37\lib\site-packages?(from?geventhttpclient>=1.5.1->locust)?(2020.4.5.1)
Requirement?already?satisfied:?brotli?in?d:\python\python37\lib\site-packages?(from?geventhttpclient>=1.5.1->locust)?(1.0.9)
Requirement?already?satisfied:?urllib3<1.27,>=1.21.1?in?d:\python\python37\lib\site-packages?(from?requests>=2.9.1->locust)?(1.26.2)
Requirement?already?satisfied:?idna<3,>=2.5?in?d:\python\python37\lib\site-packages?(from?requests>=2.9.1->locust)?(2.9)
Requirement?already?satisfied:?chardet<4,>=3.0.2?in?d:\python\python37\lib\site-packages?(from?requests>=2.9.1->locust)?(3.0.4)
Requirement?already?satisfied:?pycparser?in?d:\python\python37\lib\site-packages?(from?cffi>=1.12.2->gevent>=20.9.0->locust)?(2.20)
Collecting?MarkupSafe>=2.0
??Using?cached?MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl?(14?kB)
Using?legacy?'setup.py?install'?for?roundrobin,?since?package?'wheel'?is?not?installed.
Installing?collected?packages:?MarkupSafe,?Werkzeug,?Jinja2,?itsdangerous,?flask,?roundrobin,?pyzmq,?geventhttpclient,?Flask-Cors,?locust
??Attempting?uninstall:?MarkupSafe
????Found?existing?installation:?MarkupSafe?1.1.1
????Uninstalling?MarkupSafe-1.1.1:
??????Successfully?uninstalled?MarkupSafe-1.1.1
??Attempting?uninstall:?Werkzeug
????Found?existing?installation:?Werkzeug?1.0.1
????Uninstalling?Werkzeug-1.0.1:
??????Successfully?uninstalled?Werkzeug-1.0.1
??Attempting?uninstall:?Jinja2
????Found?existing?installation:?Jinja2?2.11.2
????Uninstalling?Jinja2-2.11.2:
??????Successfully?uninstalled?Jinja2-2.11.2
??Attempting?uninstall:?itsdangerous
????Found?existing?installation:?itsdangerous?1.1.0
????Uninstalling?itsdangerous-1.1.0:
??????Successfully?uninstalled?itsdangerous-1.1.0
??Attempting?uninstall:?flask
????Found?existing?installation:?Flask?1.1.2
????Uninstalling?Flask-1.1.2:
??????Successfully?uninstalled?Flask-1.1.2
????Running?setup.py?install?for?roundrobin?...?done
??Attempting?uninstall:?pyzmq
????Found?existing?installation:?pyzmq?22.0.3
????Uninstalling?pyzmq-22.0.3:
??????Successfully?uninstalled?pyzmq-22.0.3
??Attempting?uninstall:?geventhttpclient
????Found?existing?installation:?geventhttpclient?1.4.4
????Uninstalling?geventhttpclient-1.4.4:
??????Successfully?uninstalled?geventhttpclient-1.4.4
Successfully?installed?Flask-Cors-3.0.10?Jinja2-3.0.3?MarkupSafe-2.0.1?Werkzeug-2.0.2?flask-2.0.2?geventhttpclient-1.5.3?itsdangerous-2.0.1?locust-2.5.0?pyzmq-22.3.0?roundrobin-0.0.2
准备入门
蝗虫(locust )测试本质上是一个Python程序。这使得它非常灵活,尤其擅长实现复杂的用户流。但它也可以做简单的测试,所以让我们从这开始:
#?-*-coding:utf-8?-*-
#?**?createDate:?2021/11/19?10:31
#?**?scriptFile:?locustfiles.py
#?**?__author__:?Li?Feng
"""
注释信息:
"""
from?locust?import?HttpUser,?task
class?HelloWorldUser(HttpUser):
????@task
????def?hello_world(self):
????????self.client.get("/hello")
????????self.client.get("/world")
这个用户将一次又一次地向/hello 和/world 发出HTTP 请求。将代码放入当前目录下名为locustfile.py的文件中,并运行locust :
PS?F:\project_gitee\Test\locustProject>?locust?-f?locustfiles.py?-H?https://www.baidu.com
[2021-11-19?10:42:51,524]?jszx-zlb/INFO/locust.main:?Starting?web?interface?at?http://0.0.0.0:8089?(accepting?connections?from?all?network?interfaces)
[2021-11-19?10:42:51,538]?jszx-zlb/INFO/locust.main:?Starting?Locust?2.5.0
一旦您启动了蝗虫(locust ),打开一个浏览器并指向http://localhost:8089。界面显示如下:
名词解释:
- Number of users to simulate:设置模拟的用户总数
- Spawn rate (users spawned/second):每秒启动的虚拟用户数
- Host:待测域名
- Start swarming:开始执行
locust 脚本按钮
注意点,如果您命令行没有输入-H 加域名的话,web页面的的Host 栏就是空的,就得需要你手动输入了。
以上是web页面操作,你也可以直接使用命令行的无头操作:
PS?F:\project_gitee\Test\locustProject>?locust?--headless?--users?10?--spawn-rate?0.5?-f?locustfiles.py?-H?https://www.baidu.com
[2021-11-19?11:28:46,379]?jszx-zlb-047/INFO/locust.main:?No?run?time?limit?set,?use?CTRL+C?to?interrupt
[2021-11-19?11:28:46,380]?jszx-zlb-047/INFO/locust.main:?Starting?Locust?2.5.0
?Name??????????????????????????????????????????????????????????????????????????????#?reqs??????#?fails??|?????Avg?????Min?????Max??Median??|???req/s?failures/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
?Aggregated?????????????????????????????????????????????????????????????????????????????0?????0(0.00%)??|???????0???????0???????0???????0??|????0.00????0.00
[2021-11-19?11:28:46,383]?jszx-zlb-047/INFO/locust.runners:?Ramping?to?10?users?at?a?rate?of?0.50?per?second
(......)
忽略了一些显示报告
(......)
[2021-11-19?11:29:19,597]?jszx-zlb/INFO/locust.main:?Running?teardowns...
[2021-11-19?11:29:19,597]?jszx-zlb/INFO/locust.main:?Shutting?down?(exit?code?1),?bye.
[2021-11-19?11:29:19,597]?jszx-zlb/INFO/locust.main:?Cleaning?up?runner...
?Name??????????????????????????????????????????????????????????????????????????????#?reqs??????#?fails??|?????Avg?????Min?????Max??Median??|???req/s?failures/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------
?GET?/hello??????????????????????????????????????????????????????????????????????????6662?6662(100.00%)??|??????17???????9?????118??????16??|??200.57??200.57
?GET?/world??????????????????????????????????????????????????????????????????????????6657?6657(100.00%)??|??????17???????9?????236??????16??|??200.42??200.42
----------------------------------------------------------------------------------------------------------------------------------------------------------------
?Aggregated?????????????????????????????????????????????????????????????????????????13319?13319(100.00%)??|??????17???????9?????236??????16??|??401.00??401.00
Response?time?percentiles?(approximated)
?Type?????Name??????????????????????????????????????????????????????????????????????????????????50%????66%????75%????80%????90%????95%????98%????99%??99.9%?99.99%???100%?#?reqs
--------|--------------------------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
?GET??????/hello?????????????????????????????????????????????????????????????????????????????????16?????17?????18?????18?????24?????30?????41?????75????100????120????120???6662
?GET??????/world?????????????????????????????????????????????????????????????????????????????????16?????17?????18?????19?????24?????30?????42?????77????100????240????240???6657
--------|--------------------------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
?None?????Aggregated?????????????????????????????????????????????????????????????????????????????16?????17?????18?????19?????24?????30?????41?????76????100????120????240??13319
Error?report
?#?occurrences??????Error
----------------------------------------------------------------------------------------------------------------------------------------------------------------
?93?????????????????GET?/hello:?RemoteDisconnected('Remote?end?closed?connection?without?response')
?6572???????????????GET?/world:?HTTPError('404?Client?Error:?Not?Found?for?url:?https://www.baidu.com/world')
?6569???????????????GET?/hello:?HTTPError('404?Client?Error:?Not?Found?for?url:?https://www.baidu.com/hello')
?84?????????????????GET?/world:?RemoteDisconnected('Remote?end?closed?connection?without?response')
?1??????????????????GET?/world:?ConnectionResetError(10054,?'远程主机强迫关闭了一个现有的连接。',?None,?10054,?None)
----------------------------------------------------------------------------------------------------------------------------------------------------------------
locustfiles.py文件的编写
首先我们看下官方提供的示例:
import?time
from?locust?import?HttpUser,?task,?between
class?QuickstartUser(HttpUser):
????wait_time?=?between(1,?5)
????@task
????def?hello_world(self):
????????self.client.get("/hello")
????????self.client.get("/world")
????@task(3)
????def?view_items(self):
????????for?item_id?in?range(10):
????????????self.client.get(f"/item?id={item_id}",?name="/item")
????????????time.sleep(1)
????def?on_start(self):
????????self.client.post("/login",?json={"username":"foo",?"password":"bar"})
引入的包:
- time:时间库
- HttpUser:是表示将生成一个
HTTP 用户,这个类会在实例化后保持请求之间的用户会话 - task:修饰符,声明任务(如果没有这个就不会对这个接口运行)
- between:返回一个函数,该函数返回一个介于min_wait和max_wait之间的随机数;还有一个是
constant ,它是设置固定的时间内
名词解释:
wait_time = between(1, 5) :设置时间,最小为1,最大为5秒@task(3) :方法上装饰这个是声明这个是任务,3代表的是权重,默认权重是1name="/item" :是把该方法请求的10次,归类在item中self.client.get :是去请求接口,发送数据on_start :该方法是前置方法,优先运行的,通常放登录,登录会自动关联后续接口;还有一个后置是on_stop 方法
官方提供的例子,复制黏贴到.py文件中后,直接命令行运行即可,虽然是报错的,但是不影响观看,哈哈:
PS?F:\project_gitee\Test\locustProject>?locust?-f?locustfiles.py
实践示例
以我们自己的项目为示例(代码中会有部分改动,主要是牵扯到一些隐私信息)进行负载测试:
import?urllib3
from?locust?import?HttpUser,?TaskSet,?task,?between
class?WebsiteLmsUser(TaskSet):
????wait_time?=?between(1,?5)
????def?on_start(self):
????????urllib3.disable_warnings()
????????self.client.verify?=?False
????????self.client.headers.update({"Content-Type":?"application/json"})
????????res?=?self.client.post("/api/auth",?json={
????????????"username":?"account01",
????????????"password":?"123456",
????????????"scenario":?"web",
????????????"day":?0
????????})
????????res_json?=?res.json()["data"]["token"]
????????self.client.headers.update({"token":?res_json})
????@task
????def?user_info(self):
????????self.client.get("/api/auth")
????@task
????def?user_menu(self):
????????self.client.get("/api/auth/menu")
class?WebsiteUser(HttpUser):
????tasks?=?[WebsiteLmsUser]
????host?=?"https://api-first.com"
????min_wait?=?1000
????max_wait?=?5000
名词解释:
on_start 中是写入了登录操作WebsiteLmsUser 继承是TaskSet 类,该类是定义用户将执行的一组任务。WebsiteUser 继承了HttpUser 类,该类是将生成一个HTTP用户 ,并请求将要进行负载测试的系统tasks = [WebsiteLmsUser] 这里是locust 用户将运行python可调用类或者TaskSet类的集合host = "https://api-first.com" 指定了host,后面web页面就不需要输入了min_wait和max_wait 是定义最长和最短等待时间
命令行输入命令开始运行:
PS?F:\project_gitee\Test\locustProject>?locust?-f?locustfiles.py
[2021-11-19?18:41:14,428]?jszx-zlb/INFO/locust.main:?Starting?web?interface?at?http://0.0.0.0:8089?(accepting?connections?from?all?network?interfaces)
[2021-11-19?18:41:14,442]?jszx-zlb/INFO/locust.main:?Starting?Locust?2.5.0
[2021-11-19?18:41:25,250]?jszx-zlb/INFO/locust.runners:?Ramping?to?1?users?at?a?rate?of?1.00?per?second
[2021-11-19?18:41:25,251]?jszx-zlb/INFO/locust.runners:?All?users?spawned:?{"WebsiteUser":?1}?(1?total?users)
运行情况如下:
生成报告如下:
实际运行过程中,locust 一直执行的是负载测试,就是一直在持续运行,必须你自己手动停止,这样也能更好的检测系统接口性能的稳定性。此次只是基础的使用,这玩意还是很强大的,后续还有优化及分布等等。
以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的点赞和分享哟,谢谢!
未完,待续…
一直都在努力,希望您也是!
微信搜索公众号:就用python
作者:李 锋|编辑排版:梁莉莉
|