Locust檔案就是一般的Python檔案。唯一的需求就是它至少需要一個繼承於Locust
的類.
Locust類
Locust類代表一個使用者(如果願意,也可以是一個準備出動的蝗蟲)。Locust會為每一個模擬使用者生成一個locust類例項。同時會有一些locust類屬性被定義。
task_set
屬性
task_set
屬性是指向一個定義使用者行為的TaskSet
類,下面會有詳細的介紹。
min_wait
和max_wait
屬性
除了task_set
屬性,另外一個經常被使用的就是min_wait
和max_wait
屬性。是用於各自以毫秒為單位的最小值和最大值,一個模擬使用者將會在每個任務執行時的等待執行的時間間隔。min_wait
和max_wait
預設設定為1000
,如果不宣告的話,Locust會預設在每個任務間等待1秒
。
參考下面的程式碼,每個使用者將會在每個任務間等待5至15
秒:
from locust import Locust, TaskSet, task_set
class MyTaskSet(TaskSet):
@task
def my_task(self):
print "executing my_task"
class MyLocust(Locust):
task_set = MyTaskSet
min_wait = 5000
max_wait = 15000複製程式碼
min_wait
和max_wait
屬性可以用於重寫TaskSet
類。
weight
屬性
你可以通過同一個檔案來執行兩個locust,就像這樣:
locust -f locust_file.py WebUserLocust MobileUserLocust複製程式碼
如果你更傾向於用這種方法來執行,便可以在這些類中嘗試weight
屬性。比如,就像這樣來定義web使用者比Mobile使用者多3倍
:
class WebUserLocust(Locust):
weight = 3
...
class MobileUserLocust(Locust):
weight = 1
...複製程式碼
host
屬性
host
屬性是到要載入目標URL
的字首(如:"google.com")。通常情況下,當Locust被啟動時,在命令列中是需要通過--host
來指定的。如果host
屬性在locustfile檔案中被宣告,則在命令列中則不需要使用--host
屬性來再次宣告。
TaskSet
類
如果Locust類代表一隻準備出動的蝗蟲,那麼你可以說TaskSet
類代表蝗蟲的大腦。每一個Locust類中必須要包含一個指向TaskSet
的task_set
屬性設定。
TaskSet
就像它的名字一樣,是一個任務集合。這些任務是常規的Python呼叫,如果我們壓力測試一個拍賣網站,便可以做這些操作載入啟動頁面
、搜尋一些產品
、競標
。
當一個壓力測試被啟動時,每一個準備的Locust類例項將會開始執行它們的TaskSet
。接下來是每一個TaskSet
找到它的task
並呼叫它。它將在min_wait
和max_wait
屬性值之間隨機等待幾毫秒(除非min_wait
和max_wait
被定義在TaskSet中,在這種情況下將會使用TaskSet設定的值)。然後,它將會找到一個新task
並呼叫,再次等待,一直這樣持續下去。
宣告task
對於TaskSet
來說,典型的宣告task
的方法是直接使用task
。
參考這個例子:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def my_task(self):
print "Locust instance (%r) executing my_task" % (self.locust)
class MyLocust(Locust):
task_set = MyTaskSet複製程式碼
@task 將會獲取一個可選的權重引數,用於說明任務執行的比率。在下面的例子中 task2 將會比 task1 執行的次數多兩倍:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
min_wait = 5000
max_wait = 15000
@task(3)
def task1(self):
pass
@task(6)
def task2(self):
password
class MyLocust(Locust):
task_set = MyTaskSet複製程式碼
task
屬性
使用@task
操作符來宣告task是一種便捷的方法,並且經常是最好的方式。然而,也可以定義TaskSet
中的task通過設定tasks屬性(使用操作符@task比tasks屬性更流行)。
tasks 屬性不是python列表的呼叫就是一個
from locust import Locust, TaskSet
def my_task(l):
pass
class MyTaskSet(TaskSet):
tasks = [my_task]
class MyLocust(Locust):
task_set = MyTaskSet複製程式碼
如果task屬性被定義在列表中,每次任務被執行時,將會隨機
從 tasks 屬性中選擇。如果 tasks 是一個帶有關健字和數值呼叫的字典,被執行的任務將會被隨機選擇以數字的比率來執行。就像下面的這樣:
{my_task: 3, another_task:1}複製程式碼
my_task 將會比 another_task 多執行三倍。
TaskSet
可以巢狀
TaskSet
有一個重要的屬性就是可以被巢狀,由於真實的網站是有一定的業務層級結構的,並帶有一些子模組。巢狀的TaskSet將會幫助我們來定義更加真實的使用者行為。比如,我們可以定義TaskSet
像下面的結構
- Main user behaviour
- Index page
- Forum page
- Read thread
- Reply
- New thread
- View next page
- Read thread
- Browser categories
- Watch movies
- Filter movies
- About page
巢狀TaskSet的方法就像使用task
屬性來說明task一樣,但代替參考Python函式,你可以參考下面的TaskSet
:
class ForumPage(TaskSet):
@task(20)
def read_thread(self):
pass
@task(1)
def new_thread(self):
pass
@task(5)
def stop(self):
self.interrupt()
class UserBehaviour(TaskSet):
tasks = {ForumPage:10}
@task
def index(self):
pass複製程式碼
在上面的示例中,當UserBehaviour的TaskSet執行時,ForumPage會被選中來執行,接下來ForumPage的TaskSet將會開始執行。ForumPage的TaskSet會找到它的tasks並執行它,再等待,一直這樣持續下去。
針對上面的例子中有一個重要的事情要注意,就是在ForumPage頁面中的Stop方法中呼叫self.interrupt()
。這個做的事情是停止執行ForumPage任務並在UserBehaviour例項中繼續執行。如果在ForumPage中,我們沒有呼叫interrupt()
方法,除非被呼叫否則Locust不會呼叫ForumPage任務。但通過interrupt
函式 ,我們可以結合weight
任務來定義模擬使用者離開Forum.
也可以在類內部宣告巢狀TaskSet,通過使用@task
操作符,像宣告正常的task一樣:
class MyTaskSet(TaskSet):
@task
class SubTaskSet(TaskSet):
@task
def my_task(self):
pass複製程式碼
on_start
函式
TaskSet可以選擇宣告on_start
函式。如果這樣的話,當模擬使用者開始執行TaskSet類時,函式被呼叫。
關聯Locust
例項,或父TaskSet
例項
TaskSet
例項有locust
屬性來指向它的Locust
例項,屬性parent
用來指向它的父TaskSet
(它會指向Locsut例項,在基類TaskSet中)。
HTTP
請求
到現在為止,我們僅覆蓋了一個Locsut使用者的部分任務計劃。為了真實的壓力測試一個系統時,我們需要生成HTTP
請求。為了幫助我們實現這個功能,可以使用HttpLocust
類。當使用這個類時,每一個例項將會獲得一個用於生成Http
請求的HttpSession
例項的client
屬性。
class HttpLocust複製程式碼
表示一個用於壓力測試的孵化和攻擊系統的HTTP
使用者
。
這個使用者的行為通過task_set
屬性來定義,直接指向TaskSet
類。
這個類建立一個client
屬性,在初始化時,HTTP
客戶端支援為每一個使用者在請求間儲存session。
client=None複製程式碼
HttpSession例項在Locust初始化時被建立。client
支援cookies
,同時在請求間會儲存session。
當從HttpLocust
類繼承時,我們可以使用client
屬性來對伺服器生成HTTP
請求。下面是一個locust檔案示例用於在一個網站的兩個URL / 和 /about/ 。
from locust import HttpLocust, TaskSet, task
class MyTaskSet(TaskSet):
@task(2)
def index(self):
self.client.get('/')
@task(1)
def about(self):
self.client.get('/about/')
class MyLocust(HttpLocust):
task_set = MyTaskSet
min_wait = 5000
max_wait = 15000複製程式碼
使用上面的Locust類,每一個模擬使用者將間隔5-15秒內請求,並且/
將會比/about/
請求數量多2倍
。
細心的讀者會發現有一些奇怪,我們使用self.client
關聯HttpSession
例項,而不是TaskSet
,也不是self.locust.client
。我們可以這樣做,是因為TaskSet
類有一個屬性呼叫client
簡單的返回self.locust.client
。
使用HTTP client
每一個HttpLocust
例項在client
屬性中有一個HttpSession
例項。HttpSession
類實際上是requests.Session
的子類,可使用get
post
put
delete
head
patch
和 options
方法來生成HTTP
請求,用於Locust的資料統計。HttpSession
例項在請求間維護cookies,因此可用於登入網站並儲存session在請求之間。client
可以通過Locust例項的TaskSet例項來關聯,因此很容易獲取client並在任務中生成HTTP請求。
下面是一個生成GET
請求到 /about 路徑的示例(在這裡,我們可以假設 self 是一個TaskSet
或 HttpLocust
類的例項):
response = self.client.get("/about")
print "Response staus code:", response.status_code
print "Response content:", response.content複製程式碼
下面是一個生成POST
請求的示例:
response = self.client.post("/login", {"username": "testuser", "password": "password"})複製程式碼
安全模式
HTTP
client被配製執行在safe_mode
。這樣做是任何請求在連線超時、錯誤、相似失敗時將不會丟擲異常,而是返回一個空的假Response物件。請求將會在Locust統計中算做一次失敗。返回假Response內容屬性將會被設定為None,並且它的status_code將會是0.
手動設定請求是成功或失敗
預設情況下,請求被標記為失敗除非在返回狀態碼是OK(2XX)。大部分時間內,這個預設就是你所需要的。然而,比如在測試一個URL節點,你期待返回狀態碼為404,或者測試一個即使錯誤發生也會返回200的系統,因此,需要手工控制locust來判斷是成功還是失敗。
一個可以生成失敗請求,即使當響應程式碼是OK
,通過使用catch_response
引數和with
語法:
with client.get("/", catch_response = True) as response:
if response.content != "Success":
response.failure("Got wrong response")複製程式碼
就像一個可以使用響應為OK
的請求當做失敗來處理,一個方法就是可以使用catch_response
引數和with
語法來讓請求HTTP錯誤時,仍然統計資料為成功:
with client.get("/does_not_exist/", catch_response = True) as response:
if response.status_code = 404:
response.success()複製程式碼
使用動態引數來分組URL請求
針對網站,有一個常用的功能是獲取URL中包含一些動態引數的頁面資料。通常情況下,在Locust統計中,使用動態分組在URL中是很有意義的。通過name
引數來給HttpSession
傳遞不同的請求方法。
比如:
# Statistics for these requests will be grouped under: /blog/?id=[id]
for i in range(10):
client.get("/blog?id=%i" % i, name = "/blog?id=[id]")複製程式碼
常用庫
通常,大家想分享多個locust檔案用於分享常用的庫。在這種情況下,定義專案根目錄
用於呼叫Locsut是很重要的,建議將所有的locust檔案有些話在專案的根目錄中。
一個平鋪的結構像下面這樣:
- 專案根目錄
commonlib_conf.py
commonlib_auth.py
locustfile_web_app.py
locsutfile_api.py
locustfile_ecommerce.py
locust檔案可以呼叫常用的庫通過使用import commonlib_auth
.然而,這種方法不會從locust檔案中,清晰分辨出常用庫。
子資料夾可以有一個清晰的方法(檢視下面的示例),但是locust僅會有執行locsut檔案的位置引用相關的模組。如果你想從你的根目錄匯入(如,你執行locust命令的位置),確保在任何locust檔案中新增常用庫前有程式碼sys.path.append(os.getcwd())
,會生成匯入根目錄(如,當前工作目錄)。
- project root
__init__.py
common/
__init__.py
config.py
auth.py
locustfiles/
__init__.py
web_app.py
api.py
ecommerce.py
使用上面的專案結構,你的locust檔案可以通過下面程式碼匯入常用的庫:
sys.path.append(os.getcwd())
import common.auth複製程式碼
- 本文Locust版本
0.7.5
- 原文地址:docs.locust.io/en/latest/w…