編寫一個Locust文件

Locust文件就是一般的Python文件。唯一的需求就是它至少需要一個繼承于Locust的類.

Locust類

Locust類代表一個用戶(如果愿意,也可以是一個準(zhǔn)備出動的蝗蟲)。Locust會為每一個模擬用戶生成一個locust類實例。同時會有一些locust類屬性被定義。

task_set屬性

task_set屬性是指向一個定義用戶行為的TaskSet類,下面會有詳細(xì)的介紹。

min_waitmax_wait屬性

除了task_set屬性,另外一個經(jīng)常被使用的就是min_waitmax_wait屬性。是用于各自以毫秒為單位的最小值和最大值,一個模擬用戶將會在每個任務(wù)執(zhí)行時的等待執(zhí)行的時間間隔。min_waitmax_wait默認(rèn)設(shè)置為1000,如果不聲明的話,Locust會默認(rèn)在每個任務(wù)間等待1秒

參考下面的代碼,每個用戶將會在每個任務(wù)間等待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_waitmax_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屬性是到要加載目標(biāo)URL的前綴(如:"http://google.com")。通常情況下,當(dāng)Locust被啟動時,在命令行中是需要通過--host來指定的。如果host屬性在locustfile文件中被聲明,則在命令行中則不需要使用--host屬性來再次聲明。

TaskSet

如果Locust類代表一只準(zhǔn)備出動的蝗蟲,那么你可以說TaskSet類代表蝗蟲的大腦。每一個Locust類中必須要包含一個指向TaskSettask_set屬性設(shè)置。

TaskSet就像它的名字一樣,是一個任務(wù)集合。這些任務(wù)是常規(guī)的Python調(diào)用,如果我們壓力測試一個拍賣網(wǎng)站,便可以做這些操作加載啟動頁面搜索一些產(chǎn)品競標(biāo)

當(dāng)一個壓力測試被啟動時,每一個準(zhǔn)備的Locust類實例將會開始執(zhí)行它們的TaskSet。接下來是每一個TaskSet找到它的task并調(diào)用它。它將在min_waitmax_wait屬性值之間隨機等待幾毫秒(除非min_waitmax_wait被定義在TaskSet中,在這種情況下將會使用TaskSet設(shè)置的值)。然后,它將會找到一個新task并調(diào)用,再次等待,一直這樣持續(xù)下去。

聲明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 將會獲取一個可選的權(quán)重參數(shù),用于說明任務(wù)執(zhí)行的比率。在下面的例子中 task2 將會比 task1 執(zhí)行的次數(shù)多兩倍:

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是一種便捷的方法,并且經(jīng)常是最好的方式。然而,也可以定義TaskSet中的task通過設(shè)置tasks屬性(使用操作符@task比tasks屬性更流行)。

tasks 屬性不是python列表的調(diào)用就是一個<callbale:int>字典。tasks是python調(diào)用接收執(zhí)行task的TaskSet類實例參數(shù)。下面是一個極其簡單的示例(不會影響任何測試):

from locust import Locust, TaskSet

def my_task(l):
    pass

class MyTaskSet(TaskSet):
    tasks = [my_task]

class MyLocust(Locust):
    task_set = MyTaskSet

如果task屬性被定義在列表中,每次任務(wù)被執(zhí)行時,將會隨機tasks 屬性中選擇。如果 tasks 是一個帶有關(guān)健字和數(shù)值調(diào)用的字典,被執(zhí)行的任務(wù)將會被隨機選擇以數(shù)字的比率來執(zhí)行。就像下面的這樣:

{my_task: 3, another_task:1}

my_task 將會比 another_task 多執(zhí)行三倍。

TaskSet可以嵌套

TaskSet有一個重要的屬性就是可以被嵌套,由于真實的網(wǎng)站是有一定的業(yè)務(wù)層級結(jié)構(gòu)的,并帶有一些子模塊。嵌套的TaskSet將會幫助我們來定義更加真實的用戶行為。比如,我們可以定義TaskSet像下面的結(jié)構(gòu)

  • Main user behaviour
    • Index page
    • Forum page
      • Read thread
        • Reply
      • New thread
      • View next page
    • Browser categories
      • Watch movies
      • Filter movies
    • About page

嵌套TaskSet的方法就像使用task屬性來說明task一樣,但代替參考Python函數(shù),你可以參考下面的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

在上面的示例中,當(dāng)UserBehaviour的TaskSet執(zhí)行時,F(xiàn)orumPage會被選中來執(zhí)行,接下來ForumPage的TaskSet將會開始執(zhí)行。ForumPage的TaskSet會找到它的tasks并執(zhí)行它,再等待,一直這樣持續(xù)下去。

針對上面的例子中有一個重要的事情要注意,就是在ForumPage頁面中的Stop方法中調(diào)用self.interrupt()。這個做的事情是停止執(zhí)行ForumPage任務(wù)并在UserBehaviour實例中繼續(xù)執(zhí)行。如果在ForumPage中,我們沒有調(diào)用interrupt()方法,除非被調(diào)用否則Locust不會調(diào)用ForumPage任務(wù)。但通過interrupt函數(shù) ,我們可以結(jié)合weight任務(wù)來定義模擬用戶離開Forum.

也可以在類內(nèi)部聲明嵌套TaskSet,通過使用@task操作符,像聲明正常的task一樣:

class MyTaskSet(TaskSet):
    @task
    class SubTaskSet(TaskSet):
        @task
        def my_task(self):
            pass

on_start函數(shù)

TaskSet可以選擇聲明on_start函數(shù)。如果這樣的話,當(dāng)模擬用戶開始執(zhí)行TaskSet類時,函數(shù)被調(diào)用。

關(guān)聯(lián)Locust實例,或父TaskSet實例

TaskSet實例有locust屬性來指向它的Locust實例,屬性parent用來指向它的父TaskSet(它會指向Locsut實例,在基類TaskSet中)。

HTTP請求

到現(xiàn)在為止,我們僅覆蓋了一個Locsut用戶的部分任務(wù)計劃。為了真實的壓力測試一個系統(tǒng)時,我們需要生成HTTP請求。為了幫助我們實現(xiàn)這個功能,可以使用HttpLocust類。當(dāng)使用這個類時,每一個實例將會獲得一個用于生成Http請求的HttpSession實例的client屬性。

class HttpLocust

表示一個用于壓力測試的孵化和攻擊系統(tǒng)的HTTP 用戶

這個用戶的行為通過task_set屬性來定義,直接指向TaskSet類。

這個類創(chuàng)建一個client屬性,在初始化時,HTTP客戶端支持為每一個用戶在請求間保存session。

   client=None

HttpSession實例在Locust初始化時被創(chuàng)建。client支持cookies,同時在請求間會保存session。

當(dāng)從HttpLocust類繼承時,我們可以使用client屬性來對服務(wù)器生成HTTP請求。下面是一個locust文件示例用于在一個網(wǎng)站的兩個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秒內(nèi)請求,并且/將會比/about/請求數(shù)量多2倍

細(xì)心的讀者會發(fā)現(xiàn)有一些奇怪,我們使用self.client關(guān)聯(lián)HttpSession實例,而不是TaskSet,也不是self.locust.client。我們可以這樣做,是因為TaskSet類有一個屬性調(diào)用client簡單的返回self.locust.client

使用HTTP client

每一個HttpLocust實例在client屬性中有一個HttpSession實例。HttpSession類實際上是requests.Session的子類,可使用get post put delete head patchoptions方法來生成HTTP請求,用于Locust的數(shù)據(jù)統(tǒng)計。HttpSession實例在請求間維護(hù)cookies,因此可用于登錄網(wǎng)站并保存session在請求之間。client可以通過Locust實例的TaskSet實例來關(guān)聯(lián),因此很容易獲取client并在任務(wù)中生成HTTP請求。

下面是一個生成GET請求到 /about 路徑的示例(在這里,我們可以假設(shè) self 是一個TaskSetHttpLocust 類的實例):

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統(tǒng)計中算做一次失敗。返回假Response內(nèi)容屬性將會被設(shè)置為None,并且它的status_code將會是0.

手動設(shè)置請求是成功或失敗

默認(rèn)情況下,請求被標(biāo)記為失敗除非在返回狀態(tài)碼是OK(2XX)。大部分時間內(nèi),這個默認(rèn)就是你所需要的。然而,比如在測試一個URL節(jié)點,你期待返回狀態(tài)碼為404,或者測試一個即使錯誤發(fā)生也會返回200的系統(tǒng),因此,需要手工控制locust來判斷是成功還是失敗。

一個可以生成失敗請求,即使當(dāng)響應(yīng)代碼是OK,通過使用catch_response參數(shù)和with語法:

with client.get("/", catch_response = True) as response:
    if response.content != "Success":
        response.failure("Got wrong response")

就像一個可以使用響應(yīng)為OK的請求當(dāng)做失敗來處理,一個方法就是可以使用catch_response參數(shù)和with語法來讓請求HTTP錯誤時,仍然統(tǒng)計數(shù)據(jù)為成功:

with client.get("/does_not_exist/", catch_response = True) as response:
    if response.status_code = 404:
        response.success()

使用動態(tài)參數(shù)來分組URL請求

針對網(wǎng)站,有一個常用的功能是獲取URL中包含一些動態(tài)參數(shù)的頁面數(shù)據(jù)。通常情況下,在Locust統(tǒng)計中,使用動態(tài)分組在URL中是很有意義的。通過name參數(shù)來給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文件用于分享常用的庫。在這種情況下,定義項目根目錄用于調(diào)用Locsut是很重要的,建議將所有的locust文件有些話在項目的根目錄中。

一個平鋪的結(jié)構(gòu)像下面這樣:

  • 項目根目錄
    • commonlib_conf.py
    • commonlib_auth.py
    • locustfile_web_app.py
    • locsutfile_api.py
    • locustfile_ecommerce.py

locust文件可以調(diào)用常用的庫通過使用import commonlib_auth.然而,這種方法不會從locust文件中,清晰分辨出常用庫。

子文件夾可以有一個清晰的方法(查看下面的示例),但是locust僅會有運行l(wèi)ocsut文件的位置引用相關(guān)的模塊。如果你想從你的根目錄導(dǎo)入(如,你運行l(wèi)ocust命令的位置),確保在任何locust文件中添加常用庫前有代碼sys.path.append(os.getcwd()),會生成導(dǎo)入根目錄(如,當(dāng)前工作目錄)。

  • project root
    • __init__.py
    • common/
      • __init__.py
      • config.py
      • auth.py
    • locustfiles/
      • __init__.py
      • web_app.py
      • api.py
      • ecommerce.py

使用上面的項目結(jié)構(gòu),你的locust文件可以通過下面代碼導(dǎo)入常用的庫:

sys.path.append(os.getcwd())
import common.auth
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,948評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,766評論 18 399
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,167評論 6 13
  • Locust是什么? Locust 是一個開源負(fù)載測試工具。使用 Python 代碼定義用戶行為,也可以仿真百萬個...
    zychen143閱讀 7,202評論 1 2
  • 原文地址:RESTful web API文檔生成器 問:開發(fā)業(yè)務(wù)模塊代碼最重要的是什么?答:API接口文檔 如果你...
    brucewar閱讀 4,924評論 0 51