Locust 性能測試工具安裝使用說明


1. 介紹

    它是 一個開源性能測試工具。使用 Python 代碼來定義用戶行為。用它可以模擬百萬計的並發用戶訪問你的系統。

性能工具對比


LoadRunner 是非常有名的商業性能測試工具,功能非常強大。使用也比較復雜,目前大多介紹性能測試的書籍都以該工具為基礎,甚至有些書整本都在介紹 LoadRunner 的使用。

Jmeter 同樣是非常有名的開源性能測試工具,功能也很完善,在本書中介紹了它作為接口測試工具的使用。但實際上,它是一個標准的性能測試工具。關於Jmeter相關的資料也非常豐富,它的官方文檔也很完善。

Locust 同樣是性能測試工具,雖然官方這樣來描述它 “An open source load testing tool.” 。但其它和前面兩個工具有着較大的不同。相比前面兩個工具,功能上要差上不少,但它也並非優點全無。

  • Locust 完全基本 Python 編程語言,采用 Pure Python 描述測試腳本,並且 HTTP 請求完全基於 Requests 庫。除了 HTTP/HTTPS 協議,Locust 也可以測試其它協議的系統,只需要采用Python調用對應的庫進行請求描述即可。
  • LoadRunner 和 Jmeter 這類采用進程和線程的測試工具,都很難在單機上模擬出較高的並發壓力。Locust 的並發機制摒棄了進程和線程,采用協程(gevent)的機制。協程避免了系統級資源調度,由此可以大幅提高單機的並發能力。

正是基於這樣的特點,使我選擇使用Locust工具來做性能測試,另外一個原因是它可以讓我們換一種方式認識性能測試,可能更容易看清性能測試的本質。

我想已經成功的引起了你的興趣,那么接下來就跟着來學習Locust的使用吧。

2. Locust 安裝

Locust 是基於 Python 語言的一個性能測試庫,如果要想使用它來做性能測試必須要先安裝 Python 。
python3.6 版本安裝(略)

方式一:通過 pip 命令安裝

 
 
 
1
 
 
 
1
pip install  locust
 
 

方式二:GitHub下載安裝

GitHub項目地址:https://github.com/locustio/locust/

將項目克隆下來,通過Python 執行 setup.py 文件

 
 
 
1
 
 
 
1
python setup.py install
 
 
最后,檢查是否安裝成功。命令窗口,輸入 “locust --v” 查看版本

3. Locust 使用入門

編寫第一個性能測試腳本

創建一個locustfile.py 腳本文件
 
 
 
13
 
 
 
1
from locust import HttpLocust, TaskSet, task
2
 
                
3
# 定義用戶行為
4
class UserBehavior(TaskSet):
5
 
                
6
    @task
7
    def baidu_index(self):
8
        self.client.get("/")
9
 
                
10
class WebsiteUser(HttpLocust):
11
    task_set = UserBehavior
12
    min_wait = 3000
13
    max_wait = 6000
 
 
UserBehavior類繼承TaskSet類,用於描述用戶行為。
baidu_index() 方法表示一個用戶為行,訪問百度首頁。
使用@task裝飾該方法為一個事務。client.get()用於指請求的路徑“/”,因為是百度首頁,所以指定為根路徑。

WebsiteUser類用於設置性能測試。

  • task_set :指向一個定義的用戶行為類。
  • min_wait :執行事務之間用戶等待時間的下界(單位:毫秒)。
  • max_wait :執行事務之間用戶等待時間的上界(單位:毫秒)。

執行性能測試腳本

 
 
 
3
 
 
 
1
locust -f ./locustfile.py --host=https://www.baidu.com
2
#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting web monitor at *:8089
3
#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting Locust 0.11.1
 
 
  • -f 指定性能測試腳本文件。
  • --host 指定被測試應用的URL的地址,注意訪問百度使用的HTTPS協議。

通過瀏覽器訪問:http://127.0.0.1:8089(Locust啟動網絡監控器,默認為端口號為: 8089)

設置模擬用戶數。

設置孵化率 每秒產生(啟動)的虛擬用戶數。

點擊 “啟動” 按鈕,開始運行性能測試。

性能測試參數分析

  • Type: 請求的類型,例如GET/POST。
  • Name:請求的路徑。這里為百度首頁,即:https://www.baidu.com/
  • request:當前請求的數量。
  • fails:當前請求失敗的數量。
  • Median:中間值,單位毫秒,一半的服務器響應時間低於該值,而另一半高於該值。
  • Average:平均值,單位毫秒,所有請求的平均響應時間。
  • Min:請求的最小服務器響應時間,單位毫秒。
  • Max:請求的最大服務器響應時間,單位毫秒。
  • Content Size:單個請求的大小,單位字節。

4. Locust 腳本開發進階

Locust 中類的定義和使用

 

HttpLocust 類

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實例)的運行邏輯都會遵循如下規律:

  1. 先執行WebsiteTasks中的on_start(只執行一次),作為初始化;
  2. WebsiteTasks中隨機挑選(如果定義了任務間的權重關系,那么就是按照權重關系隨機挑選)一個任務執行;
  3. 根據Locust類min_waitmax_wait定義的間隔時間范圍(如果TaskSet類中也定義了min_wait或者max_wait,以TaskSet中的優先),在時間范圍中隨機取一個值,休眠等待;
  4. 重復2~3步驟,直至測試任務終止。
 
 
 
20
 
 
 
1
from locust import HttpLocust, TaskSet, task
2
 
                
3
class UserTask(TaskSet):
4
 
                
5
    @task
6
    def tc_index(self):
7
        self.client.get("/")
8
 
                
9
class UserOne(HttpLocust):
10
    task_set = UserTask
11
    weight = 1
12
    min_wait = 1000
13
    max_wait = 3000
14
    stop_timeout = 5
15
    host = "https://www.baidu.com"
16
 
                
17
class UserTwo(HttpLocust):
18
    weight = 2
19
    task_set = UserTask
20
    host = "https://www.baidu.com"
 
 

 

一個Locust實例被挑選執行的權重,數值越大,執行頻率越高。在一個 locustfile.py 文件中可以同時定義多個 HttpLocust 子類,然后分配他們的執行權重,例如:

然后在終端啟動測試:


 
 
 
1
 
 
 
1
locust -f locustfile.py UserOne UserTwo
 
 

 

TaskSet 類

性能測試工具要模擬用戶的業務操作,就需要通過腳本模擬用戶的行為。在前面的比喻中說到,TaskSet類好比蝗蟲的大腦,控制着蝗蟲的具體行為。

具體地,TaskSet類實現了虛擬用戶所執行任務的調度算法,包括規划任務執行順序(schedule_task)、挑選下一個任務(execute_next_task)、執行任務(execute_task)、休眠等待(wait)、中斷控制(interrupt)等等。在此基礎上,我們就可以在TaskSet子類中采用非常簡潔的方式來描述虛擬用戶的業務測試場景,對虛擬用戶的所有行為(任務)進行組織和描述,並可以對不同任務的權重進行配置。

TaskSet子類中定義任務信息時,可以采取兩種方式,@task裝飾器tasks屬性

采用@task裝飾器定義任務信息時,描述形式如下:


 
 
 
8
 
 
 
1
from locust import TaskSet, task
2
class UserBehavior(TaskSet):
3
    @task(1)
4
    def test_job1(self):
5
        self.client.get('/job1')
6
    @task(2)
7
    def test_job2(self):
8
        self.client.get('/job2')
 
 
采用 tasks屬性 定義任務信息時,描述形式如下:

 
 
 
8
 
 
 
1
from locust import TaskSet
2
def test_job1(obj):
3
    obj.client.get('/job1')
4
def test_job2(obj):
5
    obj.client.get('/job2')
6
class UserBehavior(TaskSet):
7
    tasks = {test_job1:1, test_job2:2}
8
    # tasks = [(test_job1,1), (test_job1,2)] # 兩種方式等價
 
 
在如上兩種定義任務信息的方式中,均設置了權重屬性,即執行test_job2的頻率是test_job1的兩倍。
若不指定執行任務的權重,則相當於比例為1:1
A:

 
 
 
8
 
 
 
1
from locust import TaskSet, task
2
class UserBehavior(TaskSet):
3
    @task
4
    def test_job1(self):
5
        self.client.get('/job1')
6
    @task
7
    def test_job2(self):
8
        self.client.get('/job2')
 
 
B:

 
 
 
7
 
 
 
1
from locust import TaskSet
2
def test_job1(obj):
3
    obj.client.get('/job1')
4
def test_job2(obj):
5
    obj.client.get('/job2')
6
class UserBehavior(TaskSet):
7
    tasks = [test_job1, test_job2]
 
 
在TaskSet子類中除了定義任務信息,還有一個是經常用到的,那就是on_start函數。這個和LoadRunner中的vuser_init功能相同,在正式執行測試前執行一次,主要用於完成一些初始化的工作。例如,當測試某個搜索功能,而該搜索功能又要求必須為登錄態的時候,就可以先在on_start中進行登錄操作HttpLocust使用到了requests.Session,因此后續所有任務執行過程中就都具有登錄態了。

TaskSequence類

TaskSequence類是一個TaskSet,但它的任務將按順序執行。 要定義此順序,您應該執行以下操作:

 
 
 
13
 
 
 
1
class MyTaskSequence(TaskSequence):
2
    @seq_task(1)
3
    def first_task(self):
4
        pass
5
 
                
6
    @seq_task(2)
7
    def second_task(self):
8
        pass
9
 
                
10
    @seq_task(3)
11
    @task(10)
12
    def third_task(self):
13
        pass
 
 
在上面的示例中,順序被定義為執行first_task,然后執行second_task,最后執行third_task 10次。如您所見,您可以@seq_task使用@task裝飾器進行組合,當然您也可以在TaskSequences中嵌套TaskSet,反之亦然。

公共庫

子目錄可以是一種更清晰的方法(參見下面的示例),但是locust只會導入相對於放置運行的locustfile的目錄的模塊。如果您希望從項目根目錄(即運行locust命令的位置)導入,請確保 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
使用上述項目結構,您的locust文件可以使用以下命令導入公共庫:

 
 
 
2
 
 
 
1
sys.path.append(os.getcwd())
2
import common.auth
 
 

 

HttpSession類

用於在請求之間執行Web請求和保留(會話)cookie的類(以便能夠登錄和退出網站)。 記錄每個請求,以便蝗蟲可以顯示統計信息。

每個發出請求的方法還需要兩個額外的可選參數,這些參數是特定於Locust的,並且在python-requests中不存在。這些是:

  • name - (可選)可以指定在Locust的統計信息中用作標簽而不是URL路徑的參數。這可用於將請求的不同URL分組到Locust統計信息中的單個條目中。
  • catch_response - (可選)布爾參數,如果設置,可用於發出請求,返回上下文管理器作為with語句的參數。這將允許根據響應內容將請求標記為失敗,即使響應代碼正常(2xx)。相反也有效,可以使用catch_response來捕獲請求,然后將其標記為成功,即使響應代碼不是(即500或404)。
request 方法 網址 名稱=無 catch_response = False ** kwargs 

構造並發送一個requests.Request返回requests.Response對象。

參數:
  • 方法 - 新Request對象的方法
  • url - 新Request對象的URL 
  • name - (可選)可以指定在Locust的統計信息中用作標簽而不是URL路徑的參數。這可用於將請求的不同URL分組到Locust統計信息中的單個條目中。
  • catch_response - (可選)布爾參數,如果設置,可用於發出請求,返回上下文管理器作為with語句的參數。這將允許根據響應內容將請求標記為失敗,即使響應代碼正常(2xx)。相反也有效,可以使用catch_response來捕獲請求,然后將其標記為成功,即使響應代碼不是(即500或404)。
  • params - (可選)要在查詢字符串中發送的字典或字節Request
  • data - (可選)在體內發送的字典或字節Request
  • headers - (可選)用於發送的HTTP頭的字典Request
  • cookies - (可選)用於發送的Dict或CookieJar對象Request
  • files - (可選)用於多部分編碼上載的字典'filename': file-like-objects
  • auth - (可選)Auth tuple或callable以啟用Basic / Digest / Custom HTTP Auth。
  • timeoutfloat tuple) - (可選)等待服務器在放棄之前以浮點或(連接超時,讀取超時)元組的形式發送數據的時間長度
  • allow_redirectsbool) - (可選)默認設置為True。
  • proxies - (可選)字典映射協議到代理的URL。
  • stream - (可選)是否立即下載響應內容。默認為False
  • 驗證 - (可選)是否True,將驗證SSL證書。還可以提供CA_BUNDLE路徑。
  • cert - (可選)if String,ssl客戶端證書文件(.pem)的路徑。如果Tuple,('cert','key')配對。

腳本增強

設置響應斷言
性能測試也需要設置斷言么? 某些情況下是需要,比如你在請求一個頁面時,就可以通過狀態來判斷返回的 HTTP 狀態碼是不是 200。
 
 
 
17
 
 
 
1
from locust import HttpLocust, TaskSet, task
2
 
                
3
class UserTask(TaskSet):
4
 
                
5
    @task
6
    def job(self):
7
        with self.client.get('/', catch_response = True) as response:
8
            if response.status_code == 200:
9
                response.failure('Failed!')
10
            else:
11
                response.success()
12
 
                
13
class User(HttpLocust):
14
    task_set = UserTask
15
    min_wait = 1000
16
    max_wait = 3000
17
    host = "https://www.baidu.com"
 
 

catch_response = True :布爾類型,如果設置為 True, 允許該請求被標記為失敗。

通過 client.get() 方法發送請求,將整個請求的給 response, 通過 response.status_code 得請求響應的 HTTP 狀態碼。如果不為 200 則通過 response.failure('Failed!') 打印失敗!

Locust關聯
在某些請求中,需要攜帶之前從Server端返回的參數,因此在構造請求時需要先從之前的Response中提取出所需的參數。
 
 
 
24
 
 
 
1
from lxml import etree
2
from locust import TaskSet, task, HttpLocust
3
class UserBehavior(TaskSet):
4
    @staticmethod
5
    def get_session(html):
6
        tree = etree.HTML(html)
7
        return tree.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0]
8
    @task(10)
9
    def test_login(self):
10
        html = self.client.get('/login').text
11
        username = 'user@compay.com'
12
        password = '123456'
13
        session = self.get_session(html)
14
        payload = {
15
            'username': username,
16
            'password': password,
17
            'session': session
18
        }
19
        self.client.post('/login', data=payload)
20
class WebsiteUser(HttpLocust):
21
    host = 'http://debugtalk.com'
22
    task_set = UserBehavior
23
    min_wait = 1000
24
    max_wait = 3000
 
 
Locust 參數化
所有並發虛擬用戶共享同一份測試數據,並且保證虛擬用戶使用的數據不重復。
例如,模擬3用戶並發注冊賬號,要求注冊賬號不重復,注冊完畢后結束測試;
 
 
 
31
 
 
 
1
from locust import TaskSet, task, HttpLocust
2
import queue
3
class UserBehavior(TaskSet):
4
    @task
5
    def test_register(self):
6
        try:
7
            data = self.locust.user_data_queue.get()
8
        except queue.Empty:
9
            print('account data run out, test ended.')
10
            exit(0)
11
        print('register with user: {}, pwd: {}'\
12
            .format(data['username'], data['password']))
13
        payload = {
14
            'username': data['username'],
15
            'password': data['password']
16
        }
17
        self.client.post('/register', data=payload)
18
class WebsiteUser(HttpLocust):
19
    host = 'http://debugtalk.com'
20
    task_set = UserBehavior
21
    user_data_queue = queue.Queue()
22
    for index in range(100):
23
        data = {
24
            "username": "test%04d" % index,
25
            "password": "pwd%04d" % index,
26
            "email": "test%04d@debugtalk.test" % index,
27
            "phone": "186%08d" % index,
28
        }
29
        user_data_queue.put_nowait(data)
30
    min_wait = 1000
31
    max_wait = 3000
 
 

HttpRunner使用(v2.x) 

介紹

HttpRunner 是一款面向 HTTP(S) 協議的通用測試框架,只需編寫維護一份  YAML/JSON  腳本,即可實現自動化測試、性能測試、線上監控、持續集成等多種測試需求。

安裝

 
 
 
1
 
 
 
1
 pip install httprunner
 
 

在 HttpRunner 安裝成功后,系統中會新增如下 5 個命令:

  • httprunner: 核心命令
  • ate: 曾經用過的命令(當時框架名稱為 ApiTestEngine),功能與 httprunner 完全相同
  • hrun: httprunner 的縮寫,功能與 httprunner 完全相同
  • locusts: 基於 Locust 實現性能測試
  • har2case: 輔助工具,可將標准通用的 HAR 格式(HTTP Archive)轉換為YAML/JSON格式的測試用例

httprunner、hrun、ate 三個命令完全等價,功能特性完全相同,個人推薦使用hrun命令。

運行如下命令,若正常顯示版本號,則說明 HttpRunner 安裝成功。

 
 
 
2
 
 
 
1
(locust) [root@tsbc api]# hrun -V
2
2.1.3
 
 

快速使用

抓包
使用Chrome或者火狐瀏覽器,打開要訪問的API,同時使用打開開發工具【網絡】,查看接口請求狀態
選中接口請求,右鍵導出保存為HAR格式文件,假設導出的文件名稱為  demo-quickstart.har。
生成測試用例

為了簡化測試用例的編寫工作,HttpRunner 實現了測試用例生成的功能。

首先,需要將抓取得到的數據包導出為 HAR 格式的文件,如:名稱為 demo-quickstart.har。

然后,在命令行終端中運行如下命令,即可將 demo-quickstart.har 轉換為 HttpRunner 的測試用例文件。

 
 
 
4
 
 
 
1
har2case docs/data/demo-quickstart.har -2y
2
INFO:root:Start to generate testcase.
3
INFO:root:dump testcase to YAML format.
4
INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml
 
 
使用  har2case  轉換腳本時默認轉換為 JSON 格式,加上   -2y 參數后轉換為 YAML 格式。兩種格式完全等價,YAML 格式更簡潔,JSON 格式支持的工具更豐富,大家可根據個人喜好進行選擇
經過轉換,在源 demo-quickstart.har 文件的同級目錄下生成了相同文件名稱的 YAML 格式測試用例文件 demo-quickstart.yml,其內容如下:
 
 
 
41
 
 
 
1
- config:
2
   name: testcase description
3
   variables: {}
4
 
                
5
- test:
6
   name: /api/get-token
7
   request:
8
       headers:
9
           Content-Type: application/json
10
           User-Agent: python-requests/2.18.4
11
           app_version: 2.8.6
12
           device_sn: FwgRiO7CNA50DSU
13
           os_platform: ios
14
       json:
15
           sign: 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98
16
       method: POST
17
       url: http://127.0.0.1:5000/api/get-token
18
   validate:
19
       - eq: [status_code, 200]
20
       - eq: [headers.Content-Type, application/json]
21
       - eq: [content.success, true]
22
       - eq: [content.token, baNLX1zhFYP11Seb]
23
 
                
24
- test:
25
   name: /api/users/1000
26
   request:
27
       headers:
28
           Content-Type: application/json
29
           User-Agent: python-requests/2.18.4
30
           device_sn: FwgRiO7CNA50DSU
31
           token: baNLX1zhFYP11Seb
32
       json:
33
           name: user1
34
           password: '123456'
35
       method: POST
36
       url: http://127.0.0.1:5000/api/users/1000
37
   validate:
38
       - eq: [status_code, 201]
39
       - eq: [headers.Content-Type, application/json]
40
       - eq: [content.success, true]
41
       - eq: [content.msg, user created successfully.]
 
 

現在我們只需要知道如下幾點:

  • 每個 YAML/JSON 文件對應一個測試用例(testcase)
  • 每個測試用例為一個list of dict結構,其中可能包含全局配置項(config)和若干個測試步驟(test)
  • config 為全局配置項,作用域為整個測試用例
  • test 對應單個測試步驟,作用域僅限於本身

如上便是 HttpRunner 測試用例的基本結構。

   demo-quickstart.json

 
 
 
58
 
 
 
1
[
2
    {
3
        "config": {
4
            "name": "testcase description",
5
            "variables": {}
6
        }
7
    },
8
    {
9
        "test": {
10
            "name": "/api/get-token",
11
            "request": {
12
                "url": "http://127.0.0.1:5000/api/get-token",
13
                "method": "POST",
14
                "headers": {
15
                    "User-Agent": "python-requests/2.18.4",
16
                    "device_sn": "FwgRiO7CNA50DSU",
17
                    "os_platform": "ios",
18
                    "app_version": "2.8.6",
19
                    "Content-Type": "application/json"
20
                },
21
                "json": {
22
                    "sign": "9c0c7e51c91ae963c833a4ccbab8d683c4a90c98"
23
                }
24
            },
25
            "validate": [
26
                {"eq": ["status_code", 200]},
27
                {"eq": ["headers.Content-Type", "application/json"]},
28
                {"eq": ["content.success", true]},
29
                {"eq": ["content.token", "baNLX1zhFYP11Seb"]}
30
            ]
31
        }
32
    },
33
    {
34
        "test": {
35
            "name": "/api/users/1000",
36
            "request": {
37
                "url": "http://127.0.0.1:5000/api/users/1000",
38
                "method": "POST",
39
                "headers": {
40
                    "User-Agent": "python-requests/2.18.4",
41
                    "device_sn": "FwgRiO7CNA50DSU",
42
                    "token": "baNLX1zhFYP11Seb",
43
                    "Content-Type": "application/json"
44
                },
45
                "json": {
46
                    "name": "user1",
47
                    "password": "123456"
48
                }
49
            },
50
            "validate": [
51
                {"eq": ["status_code", 201]},
52
                {"eq": ["headers.Content-Type", "application/json"]},
53
                {"eq": ["content.success", true]},
54
                {"eq": ["content.msg", "user created successfully."]}
55
            ]
56
        }
57
    }
58
]
 
 

首次運行測試用例

運行測試用例的命令為 hrun ,后面直接指定測試用例文件的路徑即可。
 
 
 
1
 
 
 
1
$ hrun docs/data/demo-quickstart-1.yml
 
 
執行性能測試使用locusts 命令執行,
 
 
 
1
 
 
 
1
locusts -f docs/data/demo-quickstart-1.yml
 
 
進階使用參考官方文檔:
https://cn.httprunner.org/
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM