1. 程式人生 > >Locust效能測試 Locust效能測試1-環境準備與基本使用 Locust效能測試2-先登入場景案例 Locust效能測試3-no-web模式和csv報告儲存 Locust效能測試4-引數關聯 Locust效能測試5-引數化批量註冊

Locust效能測試 Locust效能測試1-環境準備與基本使用 Locust效能測試2-先登入場景案例 Locust效能測試3-no-web模式和csv報告儲存 Locust效能測試4-引數關聯 Locust效能測試5-引數化批量註冊

https://www.cnblogs.com/yoyoketang/p/9638151.html

https://www.cnblogs.com/yoyoketang/p/9642242.html

https://www.cnblogs.com/yoyoketang/p/9648100.html

https://www.cnblogs.com/yoyoketang/p/9672096.html

https://www.cnblogs.com/yoyoketang/p/9683897.html

Locust效能測試1-環境準備與基本使用

前言

提到效能測試,大部分小夥伴想到的就是LR和jmeter這種工具,小編一直不太喜歡寫這種工具類的東西,我的原則是能用程式碼解決的問題,儘量不去用工具。
python裡面也有一個性能測試框架Locust,本篇簡單的介紹Locust的基本使用,希望越來越多的小夥伴能一起愛上它!

環境準備:
python3.6
windows電腦
locust

Locust簡介

Locust是一款易於使用的分散式使用者負載測試工具。它用於對網站(或其他系統)進行負載測試,並確定系統可以處理多少併發使用者。
這個想法是,在測試期間,一群蝗蟲(Locust)會攻擊你的網站。您定義了每個蝗蟲Locust(或測試使用者)的行為,並且實時地從Web UI監視群集過程。這將有助於您在讓真正的使用者進入之前進行測試並識別程式碼中的瓶頸。
Locust完全基於事件,因此可以在一臺計算機上支援數千個併發使用者。與許多其他基於事件的應用程式相比,它不使用回撥。相反,它通過協程(gevent)機制使用輕量級過程。每個蝗蟲蜂擁到你的網站實際上是在自己的程序內執行(或者是greenlet,這是正確的)。這允許您在Py​​thon中編寫非常富有表現力的場景,而不會使程式碼複雜化。

** gevent是第三方庫,通過greenlet實現協程。greenlet是python的並行處理的一個庫。 python 有一個非常有名的庫叫做 stackless ,用來做併發處理, 主要是弄了個叫做tasklet的微執行緒的東西, 而greenlet 跟stackless的最大區別是greenlet需要你自己來處理執行緒切換, 就是說,你需要自己指定現在執行哪個greenlet再執行哪個greenlet。**

環境安裝

Locust支援Python 2.7, 3.4, 3.5, and 3.6的版本,小編的環境是python3.6直接用pip安裝就行

 

 

快速開始

locust裡面請求是基於requests的,每個方法請求和requests差不多,請求引數、方法、響應物件和requests一樣的使用,之前學過requests庫的,這裡就非常簡單了

  • requests.get 對應client.get
  • requests.post 對應client.post
# 儲存為demo.py
# coding:utf-8
from locust import HttpLocust,TaskSet,task

class BlogDemo(TaskSet):
    '''使用者行為:開啟我的部落格首頁demo'''
    @task(1)
    def open_blog(self):
        # 定義requests的請求頭
        header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}

        r = self.client.get("/yoyoketang",  headers=header, verify=False)
        print(r.status_code)
        assert r.status_code == 200

class websitUser(HttpLocust):
    task_set = BlogDemo
    min_wait = 3000  # 單位毫秒
    max_wait = 6000  # 單位毫秒

if __name__ == "__main__":
    import os
    os.system("locust -f demo.py --host=https://www.cnblogs.com")

 

 

程式碼註解:
新建一個類BlogDemo(TaskSet),繼承TaskSet,該類下面寫一些準備請求的行為(訪問的介面)
裡面的self.client呼叫get和post方法,跟requests是一樣的
@task裝飾該方法表示為使用者行為。括號裡面引數表示該行為挑選執行的權重,數值越大,執行頻率越高,不設定預設是1

WebsiteUser()類用於設定效能測試。
task_set :指向一個定義了的使用者行為類。
min_wait :使用者執行任務之間等待時間的下界,單位:毫秒。
max_wait :使用者執行任務之間等待時間的上界,單位:毫秒。

啟動locust

啟動locust可以直接在pycharm裡面執行上面的程式碼,執行後編輯器出現兩行
[2018-09-12 23:23:57,500] DESKTOP-HJ487C8/INFO/locust.main: Starting web monitor at *:8089
[2018-09-12 23:23:57,500] DESKTOP-HJ487C8/INFO/locust.main: Starting Locust 0.9.0

也可以通過cmd執行

$ locust -f demo.py --host=https://www.cnblogs.com

  • -f 引數是指定執行的指令碼
  • --host是指定執行專案的host地址,這裡用的https://www.cnblogs.com,程式碼裡面get訪問的是"/yoyoketang",拼接起來就是完整地址了

8089是該服務啟動的埠號。由於是在本機上搭建的locust,所以可以直接在瀏覽器輸入http://localhost:8089/開啟,
如果是在其它機器上搭建的locust服務,那就通過http://其它機器IP:8089/開啟

 

Number of users to simulate 設定虛擬使用者總數
Hatch rate (users spawned/second) 每秒啟動虛擬使用者數
點選Start swarming 開始執行效能測試


效果展示

設定虛擬使用者數30,每秒啟動5個使用者,點選Start swarming 開始執行

 

Type:請求型別;
Name:請求路徑;
requests:當前請求的數量;
fails:當前請求失敗的數量;
Median:中間值,單位毫秒,一般伺服器響應時間低於該值,而另一半高於該值;
Average:所有請求的平均響應時間,毫秒;
Min:請求的最小的伺服器響應時間,毫秒;
Max:請求的最大伺服器響應時間,毫秒;
Content Size:單個請求的大小,單位位元組;
reqs/sec:每秒鐘請求的個數。


點stop可以停止測試

 

三個圖示分別是

吞吐量/每秒響應事務數(rps)實時統計
平均響應時間/平均事務數實時統計
虛擬使用者數執行

 ===============================================================================================================

 ===============================================================================================================

 ===============================================================================================================

 

Locust效能測試2-先登入場景案例

 

前言

有很多網站不登入的話,是無法訪問到裡面的頁面的,這就需要先登入了
實現場景:先登入(只登入一次),然後訪問頁面->我的地盤頁->產品頁->專案頁

官方案例

下面是一個簡單的locustfile.py的簡單示例:

from locust import HttpLocust, TaskSet

def login(l):
    l.client.post("/login", {"username":"ellen_key", "password":"education"})

def logout(l):
    l.client.post("/logout", {"username":"ellen_key", "password":"education"})

def index(l):
    l.client.get("/")

def profile(l):
    l.client.get("/profile")

class UserBehavior(TaskSet):
    tasks = {index: 2, profile: 1}

    def on_start(self):
        login(self)

    def on_stop(self):
        logout(self)

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 5000
    max_wait = 9000

這裡我們定義了許多Locust任務,它們是帶有一個引數(Locust類例項)的普通Python callables 。這些任務收集在tasks屬性的TaskSet類下 。然後我們有一個代表使用者的 類,我們在其中定義模擬使用者在執行任務之間應該等待多長時間,以及哪個 類應該定義使用者的“行為”。 類可以繼承HttpLocust、TaskSet、TaskSet

HttpLocust類從繼承 Locust的類,並把它新增一個客戶端屬性,它是的一個例項 HttpSession,可用於使HTTP請求。

另一種我們可以宣告任務的方法,通常是更方便,就是使用 @task裝飾器。以下程式碼與上述程式碼相同:

from locust import HttpLocust, TaskSet, task

class UserBehavior(TaskSet):
    def on_start(self):
        """ on_start is called when a Locust start before any task is scheduled """
        self.login()

    def on_stop(self):
        """ on_stop is called when the TaskSet is stopping """
        self.logout()

    def login(self):
        self.client.post("/login", {"username":"ellen_key", "password":"education"})

    def logout(self):
        self.client.post("/logout", {"username":"ellen_key", "password":"education"})

    @task(2)
    def index(self):
        self.client.get("/")

    @task(1)
    def profile(self):
        self.client.get("/profile")

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 5000
    max_wait = 9000

在Locust類(以及HttpLocust 因為它是一個子類),也可以讓一個在指定最小和最大等待時間毫秒,每個模擬使用者之間的任務執行(min_wait和MAX_WAIT)以及其他使用者的行為。預設情況下,時間是在min_wait和max_wait之間統一隨機選擇的,但是可以通過將wait_function設定為任意函式來使用任何使用者定義的時間分佈。例如,對於指數分佈的等待時間平均為1秒:

import random

class WebsiteUser(HttpLocust):
    task_set = UserBehaviour
    wait_function = lambda self: random.expovariate(1)*1000

專案例項

上面的官方案例只是一些虛擬碼,不能在真實的環境中跑起來,接下來把上面的理論執行用到真實的專案環境中
http協議是無狀態的,所以登入請求和登入後的請求它是獨立的,但是登入後的請求需要依賴先登入拿到cookies,才能保持登入狀態,這個在之前python介面自動化裡面可以用session來解決

s = requests.session()

 

HttpLocust類從繼承 Locust的類,並把它新增一個客戶端屬性,它是的一個例項 HttpSession,可用於使HTTP請求,這就相當於它自動使用了session機制,類似於client = requests.session()
所以後面的請求,直接拿client.get()、client.post()請求就可以了

# 儲存為locustfile.py
# coding=utf-8
from locust import HttpLocust, TaskSet, task

'''
實現場景:先登入(只登入一次),然後訪問->我的地盤頁->產品頁->專案頁
訪問我的地盤頁面權重為2,產品頁和專案頁權重各為1
***作者:上海-悠悠 QQ群:588402570**
'''

class UserBehavior(TaskSet):
    '''蝗蟲行為類'''
    def _login(self):
        '''登入方法'''
        # host = 'http://192.168.x.xx:80'  # 禪道的伺服器地
        loginUrl ="/zentao/user-login.html/"
        h = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
            "Content-Type": "application/x-www-form-urlencoded",
            }
        body = {"account": "yoyo",  # 你自己的賬號
                "password": "******",    # 你自己的密碼
                "keepLogin[]": "on",
                "referer": "/zentao/my/"
                }
        r = self.client.post(loginUrl, data=body, headers=h)
        print(r.text)
        assert "parent.location='/zentao/index.html'" in r.text

    def on_start(self):
        '''任務開始準備工作:只登入一次'''
        self._login()

    # 任務1-我的地盤
    @task(2)
    def zentao_my(self):
        print("---訪問頁面-我的地盤---")
        r = self.client.get("/zentao/my/")
        assert "我的地盤" in r.text

    # 任務2-產品頁
    @task(1)
    def zentao_product(self):
        print("---訪問頁面-產品頁---")
        r = self.client.get("/zentao/product-browse.html/")
        assert "需求列表" in r.text

    # 任務3-專案
    @task(1)
    def zentao_prject(self):
        print("---訪問頁面-專案---")
        r = self.client.get("/zentao/project/")
        assert "專案首頁" in r.text


class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 1000
    max_wait = 1000

if __name__ == "__main__":
    import os
    os.system("locust -f locustfile.py --host=http://192.168.x.xx:80")

 ===============================================================================================================

 ===============================================================================================================

 ===============================================================================================================

 

 

Locust效能測試3-no-web模式和csv報告儲存

 

前言

前面是在web頁面操作,需要手動的點start啟動,結束的時候也需要手工去點stop,沒法自定義執行時間,這就不太方便。
locust提供了命令列執行的方法,不啟動web頁面也能執行,這就是no-web模式啟動

無web-UI模式

在沒有Web UI的情況下執行locust - 可以開啟cmd 通過使用--no-web引數,

  • -c指定要生成的Locust使用者數
  • -r每秒啟動虛擬使用者數

先cd到腳本當前目錄,然後執行指令

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1

# 設定執行時間

如果要指定測試的執行時間,可以使用--run-time

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1 --run-time 10

 

或使用-t引數

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1 -t 10

 

執行時間單位,如果不寫單位預設是s,也可以指定小時h,分鐘m,可以參考以下時間格式

  • 10s 10秒(不寫單位預設s)
  • 5m 表示5分鐘
  • 1h 1小時
  • 1m30s 1分30秒

匯出csv格式報告

您可能希望通過CSV檔案儲存的Locus結果。在這種情況下,有兩種方法可以做到這一點。

首先,使用Web UI執行Locust時,您可以在“下載資料”選項卡下點選下載CSV檔案。

  • Download request statistics CSV
  • Download response time distribution CSV
  • Download exceptions CSV

 

 

 ===============================================================================================================

 ===============================================================================================================

 ===============================================================================================================

 

Locust效能測試4-引數關聯

 

前言

前面【Locust效能測試2-先登入場景案例】講了登入的案例,這種是直接傳賬號和密碼就能登入了,有些登入的網站會複雜一點,
需要先從頁面上動態獲取引數,作為登入介面的請求引數,如【學信網:https://account.chsi.com.cn/passport/login】的登入介面請求引數

請求引數

需要先發個get請求,從返回的html頁面中解析出需要的資料

lt : LT-277623-5ldGTLqQhP4foKihHUlgfKPeGGyWVI
execution: e1s1

 

備註:
lt 引數是每次開啟瀏覽器,訪問登入首頁時服務端會返回一個新的資料
execution 引數是表示網站重新整理次數,可以重新整理下再登入,就變成 e2s1了

 

<input class="btn_login" name="submit" accesskey="l" value="登入" tabindex="4" type="submit" title="登入" />
                            
<div class="account-oprate clearfix">
       <a class="find-yhm" href="https://account.chsi.com.cn/account/password!rtvlgname">找回使用者名稱</a>
       <a class="find-mm" href="https://account.chsi.com.cn/account/password!retrive">找回密碼</a>
       <a href="https://account.chsi.com.cn/account/preregister.action?from=account-login" class="regist-btn">註冊</a>
</div>
<input type="hidden" name="lt" value="LT-279621-fnisPBt0FVGNFrfWzJJqhTEyw6VkfH" />
<input type="hidden" name="execution" value="e2s1" />
<input type="hidden" name="_eventId" value="submit" />

locustfile3.py程式碼

前面用篇專門講了requests實現介面的引數關聯案例,這裡直接轉化成locust指令碼就行了

 

# coding:utf-8
from locust import HttpLocust, TaskSet, task
from lxml import etree

class LoginDemo(TaskSet):
    '''使用者行為描述'''
    def get_it_execution(self):
        result = {}
        h1 = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
        }
        self.client.headers.update(h1)
        r = self.client.get("/passport/login", verify=False)
        # 從返回html頁面,解析出lt、execution
        dom = etree.HTML(r.content.decode("utf-8"))
        try:
            result["lt"] = dom.xpath('//input[@name="lt"]')[0].get("value")
            result["execution"] = dom.xpath('//input[@name="execution"]')[0].get("value")
            print(result)
        except:
            print("lt、execution引數獲取失敗!")
        return result

    def login(self, user, psw):
        result = self.get_it_execution()
        loginurl = "/passport/login"
        h2 = {
            "Referer": loginurl,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Origin": "https://account.chsi.com.cn",
            "Content-Length": "119",
            "Cache-Control": "max-age=0",
            "Upgrade-Insecure-Requests": "1",
            "Content-Type": "application/x-www-form-urlencoded"
            }
        body = {
            "username": user,
            "password": psw,
            "rememberMe": "true",
            "lt": result["lt"],
            "execution": result["execution"],
            "_eventId": "submit"
        }
        self.client.headers.update(h2)
        print(self.client.headers)
        r1 = self.client.post(loginurl, data=body, verify=False)
        # print(r1.text)

    @task(1)
    def test_login(self):
        # 測試資料
        user = "13888888888"
        psw = "111111"
        self.login(user, psw)

class websitUser(HttpLocust):
    task_set = LoginDemo
    host = "https://account.chsi.com.cn"
    min_wait = 3000  # 單位毫秒
    max_wait = 6000  # 單位毫秒

if __name__ == "__main__":
    import os
    os.system("locust -f locustfile3.py")

 ===============================================================================================================

 ===============================================================================================================

 ===============================================================================================================

Locust效能測試5-引數化批量註冊

 

前言

實現場景:所有併發虛擬使用者共享同一份測試資料,並且保證虛擬使用者使用的資料不重複。
例如,模擬10使用者併發註冊賬號,總共有100個手機號,要求註冊賬號不重複,註冊完畢後結束測試

準備資料

虛擬使用者數,可以在啟動的時候設定,這裡先裝備好註冊需要用到的手機號,可以用list生成

# 生成測試手機號
demo = 13812120000
teldatas = [str(demo+i) for i in range(100)]
print(teldatas)

將測試資料加到佇列

import queue

# 生成測試手機號
demo = 13812120000
teldatas = [str(demo+i) for i in range(100)]
# print(teldatas)

# 新增到佇列
telqueue = queue.Queue()
for i in teldatas:
    telqueue.put_nowait(i)

註冊demo參考

以下是一個簡單的demo模型,具體的註冊介面替換過去就可以了

# 儲存為 locustfile4.py
#  coding=utf-8
from locust import HttpLocust, TaskSet, task
import queue

class test_taskset(TaskSet):

    @task
    def register(self):
        try:
            tel = self.locust.telqueue.get()  # 獲取佇列裡的資料
            print(tel)
        except queue.Empty:                     # 佇列取空後,直接退出
            print("no data exist")
            exit(0)
        print("當前註冊手機號:%s" % tel)
        # body = {
        #     "username": tel,
        #     "psd": "123456",
        #     }
        # self.client.post("/register", data=body)   # POST方法傳送請求


class test_run(HttpLocust):
    host = 'http://192.168.1.xxx:80'
    task_set = test_taskset
    # 生成測試手機號
    teldatas = [str(13812120000+i) for i in range(100)]

    # 新增到佇列
    telqueue = queue.Queue()
    for i in teldatas:
        telqueue.put_nowait(i)

if __name__ == "__main__":
    import os
    os.system("locust -f locustfile4.py")

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

前言

有很多網站不登入的話,是無法訪問到裡面的頁面的,這就需要先登入了
實現場景:先登入(只登入一次),然後訪問頁面->我的地盤頁->產品頁->專案頁

官方案例

下面是一個簡單的locustfile.py的簡單示例:

前言

前面是在web頁面操作,需要手動的點start啟動,結束的時候也需要手工去點stop,沒法自定義執行時間,這就不太方便。
locust提供了命令列執行的方法,不啟動web頁面也能執行,這就是no-web模式啟動

無web-UI模式

在沒有Web UI的情況下執行locust - 可以開啟cmd 通過使用--no-web引數,

  • -c指定要生成的Locust使用者數
  • -r每秒啟動虛擬使用者數

先cd到腳本當前目錄,然後執行指令

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1

# 設定執行時間

如果要指定測試的執行時間,可以使用--run-time

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1 --run-time 10

 

或使用-t引數

locust -f locustfile.py --host=http://192.168.x.xx:80 --no-web -c 1 -r 1 -t 10

 

執行時間單位,如果不寫單位預設是s,也可以指定小時h,分鐘m,可以參考以下時間格式

  • 10s 10秒(不寫單位預設s)
  • 5m 表示5分鐘
  • 1h 1小時
  • 1m30s 1分30秒

匯出csv格式報告

您可能希望通過CSV檔案儲存的Locus結果。在這種情況下,有兩種方法可以做到這一點。

首先,使用Web UI執行Locust時,您可以在“下載資料”選項卡下點選下載CSV檔案。

  • Download request statistics CSV
  • Download response time distribution CSV
  • Download exceptions CSV

前言

前面【Locust效能測試2-先登入場景案例】講了登入的案例,這種是直接傳賬號和密碼就能登入了,有些登入的網站會複雜一點,
需要先從頁面上動態獲取引數,作為登入介面的請求引數,如【學信網:https://account.chsi.com.cn/passport/login】的登入介面請求引數

請求引數

需要先發個get請求,從返回的html頁面中解析出需要的資料

lt : LT-277623-5ldGTLqQhP4foKihHUlgfKPeGGyWVI
execution: e1s1

 

備註:
lt 引數是每次開啟瀏覽器,訪問登入首頁時服務端會返回一個新的資料
execution 引數是表示網站重新整理次數,可以重新整理下再登入,就變成 e2s1了

前言

實現場景:所有併發虛擬使用者共享同一份測試資料,並且保證虛擬使用者使用的資料不重複。
例如,模擬10使用者併發註冊賬號,總共有100個手機號,要求註冊賬號不重複,註冊完畢後結束測試

準備資料