1. 介紹html
LoadRunner 是很是有名的商業性能測試工具,功能很是強大。使用也比較複雜,目前大多介紹性能測試的書籍都以該工具爲基礎,甚至有些書整本都在介紹 LoadRunner 的使用。python
Jmeter 一樣是很是有名的開源性能測試工具,功能也很完善,在本書中介紹了它做爲接口測試工具的使用。但實際上,它是一個標準的性能測試工具。關於Jmeter相關的資料也很是豐富,它的官方文檔也很完善。ios
Locust 一樣是性能測試工具,雖然官方這樣來描述它 「An open source load testing tool.」 。但其它和前面兩個工具備着較大的不一樣。相比前面兩個工具,功能上要差上很多,但它也並不是優勢全無。git
正是基於這樣的特色,使我選擇使用Locust工具來作性能測試,另一個緣由是它可讓咱們換一種方式認識性能測試,可能更容易看清性能測試的本質。github
我想已經成功的引發了你的興趣,那麼接下來就跟着來學習Locust的使用吧。web
方式一:經過 pip 命令安裝算法
pip install locust
方式二:GitHub下載安裝編程
GitHub項目地址:https://github.com/locustio/locust/json
將項目克隆下來,經過Python 執行 setup.py 文件api
python setup.py install
from locust import HttpLocust, TaskSet, task
# 定義用戶行爲
class UserBehavior(TaskSet):
def baidu_index(self):
self.client.get("/")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 3000
max_wait = 6000
WebsiteUser類用於設置性能測試。
locust -f ./locustfile.py --host=https://www.baidu.com
#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting web monitor at *:8089
#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting Locust 0.11.1
經過瀏覽器訪問:http://127.0.0.1:8089(Locust啓動網絡監控器,默認爲端口號爲: 8089)
設置模擬用戶數。
設置孵化率 每秒產生(啓動)的虛擬用戶數。
點擊 「啓動」 按鈕,開始運行性能測試。
性能測試參數分析
在Locust類
中,具備一個client
屬性,它對應着虛擬用戶做爲客戶端所具有的請求能力,也就是咱們常說的請求方法。一般狀況下,咱們不會直接使用Locust
類,由於其client
屬性沒有綁定任何方法。所以在使用Locust
時,須要先繼承Locust類
,而後在繼承子類中的client
屬性中綁定客戶端的實現類。
對於常見的HTTP(S)
協議,Locust
已經實現了HttpLocust
類,其client
屬性綁定了HttpSession
類,而HttpSession
又繼承自requests.Session
。所以在測試HTTP(S)
的Locust腳本
中,咱們能夠經過client
屬性來使用Python requests
庫的全部方法,包括GET/POST/HEAD/PUT/DELETE/PATCH
等,調用方式也與requests
徹底一致。另外,因爲requests.Session
的使用,所以client
的方法調用之間就自動具備了狀態記憶的功能。常見的場景就是,在登陸系統後能夠維持登陸狀態的Session
,從然後續HTTP請求操做都能帶上登陸態。
而對於HTTP(S)
之外的協議,咱們一樣可使用Locust
進行測試,只是須要咱們自行實現客戶端。在客戶端的具體實現上,可經過註冊事件的方式,在請求成功時觸發events.request_success
,在請求失敗時觸發events.request_failure
便可。而後建立一個繼承自Locust類
的類,對其設置一個client
屬性並與咱們實現的客戶端進行綁定。後續,咱們就能夠像使用HttpLocust類
同樣,測試其它協議類型的系統。
在Locust類
中,除了client
屬性,還有幾個屬性須要關注下:
task_set
: 指向一個TaskSet
類,TaskSet
類定義了用戶的任務信息,該屬性爲必填;max_wait/min_wait
: 每一個用戶執行兩個任務間隔時間的上下限(毫秒),具體數值在上下限中隨機取值,若不指定則默認間隔時間固定爲1秒;host
:被測系統的host,當在終端中啓動locust
時沒有指定--host
參數時纔會用到;weight
:同時運行多個Locust類
時會用到,用於控制不一樣類型任務的執行權重。測試開始後,每一個虛擬用戶(Locust實例
)的運行邏輯都會遵循以下規律:
WebsiteTasks
中的on_start
(只執行一次),做爲初始化;WebsiteTasks
中隨機挑選(若是定義了任務間的權重關係,那麼就是按照權重關係隨機挑選)一個任務執行;Locust類
中min_wait
和max_wait
定義的間隔時間範圍(若是TaskSet類
中也定義了min_wait
或者max_wait
,以TaskSet
中的優先),在時間範圍中隨機取一個值,休眠等待;2~3
步驟,直至測試任務終止。from locust import HttpLocust, TaskSet, task
class UserTask(TaskSet):
def tc_index(self):
self.client.get("/")
class UserOne(HttpLocust):
task_set = UserTask
weight = 1
min_wait = 1000
max_wait = 3000
stop_timeout = 5
host = "https://www.baidu.com"
class UserTwo(HttpLocust):
weight = 2
task_set = UserTask
host = "https://www.baidu.com"
一個Locust實例被挑選執行的權重,數值越大,執行頻率越高。在一個 locustfile.py 文件中能夠同時定義多個 HttpLocust 子類,而後分配他們的執行權重,例如:
而後在終端啓動測試:
locust -f locustfile.py UserOne UserTwo
性能測試工具要模擬用戶的業務操做,就須要經過腳本模擬用戶的行爲。在前面的比喻中說到,TaskSet類
比如蝗蟲的大腦,控制着蝗蟲的具體行爲。
具體地,TaskSet類
實現了虛擬用戶所執行任務的調度算法,包括規劃任務執行順序(schedule_task
)、挑選下一個任務(execute_next_task
)、執行任務(execute_task
)、休眠等待(wait
)、中斷控制(interrupt
)等等。在此基礎上,咱們就能夠在TaskSet
子類中採用很是簡潔的方式來描述虛擬用戶的業務測試場景,對虛擬用戶的全部行爲(任務)進行組織和描述,並能夠對不一樣任務的權重進行配置。
在TaskSet
子類中定義任務信息時,能夠採起兩種方式,@task裝飾器
和tasks屬性
。
採用@task裝飾器
定義任務信息時,描述形式以下:
from locust import TaskSet, task
class UserBehavior(TaskSet):
1) (
def test_job1(self):
self.client.get('/job1')
2) (
def test_job2(self):
self.client.get('/job2')
tasks屬性
定義任務信息時,描述形式以下:
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = {test_job1:1, test_job2:2}
# tasks = [(test_job1,1), (test_job1,2)] # 兩種方式等價
test_job2
的頻率是test_job1
的兩倍。1:1
。from locust import TaskSet, task
class UserBehavior(TaskSet):
def test_job1(self):
self.client.get('/job1')
def test_job2(self):
self.client.get('/job2')
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = [test_job1, test_job2]
class MyTaskSequence(TaskSequence):
1) (
def first_task(self):
pass
2) (
def second_task(self):
pass
3) (
10) (
def third_task(self):
pass
@seq_task
使用@task
裝飾器進行組合,固然您也能夠在TaskSequences中嵌套TaskSet,反之亦然。sys.path.append(os.getcwd())
在導入任何公共庫以前寫入您的locust文件 - 這將使項目成爲root(即當前正在工做)目錄)可導入。
__init__.py
common/
__init__.py
config.py
auth.py
locustfiles/
__init__.py
web_app.py
api.py
ecommerce.py
sys.path.append(os.getcwd())
import common.auth
每一個發出請求的方法還須要兩個額外的可選參數,這些參數是特定於Locust的,而且在python-requests中不存在。這些是:
request
(
方法
,
網址
,
名稱=無
,
catch_response = False
,
** kwargs
)
構造併發送一個requests.Request
。返回requests.Response
對象。
參數: |
|
---|
from locust import HttpLocust, TaskSet, task
class UserTask(TaskSet):
def job(self):
with self.client.get('/', catch_response = True) as response:
if response.status_code == 200:
response.failure('Failed!')
else:
response.success()
class User(HttpLocust):
task_set = UserTask
min_wait = 1000
max_wait = 3000
host = "https://www.baidu.com"
catch_response = True :布爾類型,若是設置爲 True, 容許該請求被標記爲失敗。
經過 client.get() 方法發送請求,將整個請求的給 response, 經過 response.status_code 得請求響應的 HTTP 狀態碼。若是不爲 200 則經過 response.failure('Failed!') 打印失敗!
from lxml import etree
from locust import TaskSet, task, HttpLocust
class UserBehavior(TaskSet):
def get_session(html):
tree = etree.HTML(html)
return tree.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0]
10) (
def test_login(self):
html = self.client.get('/login').text
username = 'user@compay.com'
password = '123456'
session = self.get_session(html)
payload = {
'username': username,
'password': password,
'session': session
}
self.client.post('/login', data=payload)
class WebsiteUser(HttpLocust):
host = 'http://debugtalk.com'
task_set = UserBehavior
min_wait = 1000
max_wait = 3000
from locust import TaskSet, task, HttpLocust
import queue
class UserBehavior(TaskSet):
def test_register(self):
try:
data = self.locust.user_data_queue.get()
except queue.Empty:
print('account data run out, test ended.')
exit(0)
print('register with user: {}, pwd: {}'\
.format(data['username'], data['password']))
payload = {
'username': data['username'],
'password': data['password']
}
self.client.post('/register', data=payload)
class WebsiteUser(HttpLocust):
host = 'http://debugtalk.com'
task_set = UserBehavior
user_data_queue = queue.Queue()
for index in range(100):
data = {
"username": "test%04d" % index,
"password": "pwd%04d" % index,
"email": "test%04d@debugtalk.test" % index,
"phone": "186%08d" % index,
}
user_data_queue.put_nowait(data)
min_wait = 1000
max_wait = 3000
YAML/JSON
腳本,便可實現自動化測試、性能測試、線上監控、持續集成等多種測試需求。
pip install httprunner
在 HttpRunner 安裝成功後,系統中會新增以下 5 個命令:
httprunner、hrun、ate 三個命令徹底等價,功能特性徹底相同,我的推薦使用hrun
命令。
運行以下命令,若正常顯示版本號,則說明 HttpRunner 安裝成功。
(locust) [root@tsbc api]# hrun -V
2.1.3
爲了簡化測試用例的編寫工做,HttpRunner 實現了測試用例生成的功能。
首先,須要將抓取獲得的數據包導出爲 HAR 格式的文件,如:名稱爲 demo-quickstart.har。
而後,在命令行終端中運行以下命令,便可將 demo-quickstart.har 轉換爲 HttpRunner 的測試用例文件。
har2case docs/data/demo-quickstart.har -2y
INFO:root:Start to generate testcase.
INFO:root:dump testcase to YAML format.
INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml
config
name testcase description
variables
test
name /api/get-token
request
headers
Content-Type application/json
User-Agent python-requests/2.18.4
app_version2.8.6
device_sn FwgRiO7CNA50DSU
os_platform ios
json
sign 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98
method POST
url http //127.0.0.1 5000/api/get-token
validate
eq status_code 200
eq headers.Content-Type application/json
eq content.success true
eq content.token baNLX1zhFYP11Seb
test
name /api/users/1000
request
headers
Content-Type application/json
User-Agent python-requests/2.18.4
device_sn FwgRiO7CNA50DSU
token baNLX1zhFYP11Seb
json
name user1
password'123456'
method POST
url http //127.0.0.1 5000/api/users/1000
validate
eq status_code 201
eq headers.Content-Type application/json
eq content.success true
eq content.msg user created successfully.
如今咱們只須要知道以下幾點:
如上即是 HttpRunner 測試用例的基本結構。
demo-quickstart.json
[
{
"config": {
"name": "testcase description",
"variables": {}
}
},
{
"test": {
"name": "/api/get-token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"User-Agent": "python-requests/2.18.4",
"device_sn": "FwgRiO7CNA50DSU",
"os_platform": "ios",
"app_version": "2.8.6",
"Content-Type": "application/json"
},
"json": {
"sign": "9c0c7e51c91ae963c833a4ccbab8d683c4a90c98"
}
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["headers.Content-Type", "application/json"]},
{"eq": ["content.success", true]},
{"eq": ["content.token", "baNLX1zhFYP11Seb"]}
]
}
},
{
"test": {
"name": "/api/users/1000",
"request": {
"url": "http://127.0.0.1:5000/api/users/1000",
"method": "POST",
"headers": {
"User-Agent": "python-requests/2.18.4",
"device_sn": "FwgRiO7CNA50DSU",
"token": "baNLX1zhFYP11Seb",
"Content-Type": "application/json"
},
"json": {
"name": "user1",
"password": "123456"
}
},
"validate": [
{"eq": ["status_code", 201]},
{"eq": ["headers.Content-Type", "application/json"]},
{"eq": ["content.success", true]},
{"eq": ["content.msg", "user created successfully."]}
]
}
}
]
hrun
,後面直接指定測試用例文件的路徑便可。
$ hrun docs/data/demo-quickstart-1.yml
locusts -f docs/data/demo-quickstart-1.yml