最近一直在使用Locust進(jìn)行壓力測(cè)試乖杠,因此想總結(jié)一下學(xué)習(xí)和實(shí)踐的一些成果币狠。Locust官方文檔
版本:
python: 3.*
locust: 0.9.0
1.不同類(lèi)型的模擬用戶(hù)
考慮一種測(cè)試場(chǎng)景:如果我們想測(cè)試一款游戲近哟,需要并發(fā)100個(gè)人,并且使其中10個(gè)人在大廳閑逛景醇,另外90個(gè)人玩比賽闲坎,用locust框架應(yīng)該怎么實(shí)現(xiàn)呢?框架的命令行有提示locust [options] [LocustClass [LocustClass2 ...]]
當(dāng)我們使用框架運(yùn)行一個(gè)測(cè)試腳本時(shí)蟆湖,如果腳本中只有一個(gè)Locust類(lèi)故爵,則框架會(huì)以這個(gè)類(lèi)作為模擬用戶(hù)的模板;如果該腳本中不止一個(gè)Locust類(lèi)隅津,則需要指定類(lèi)名诬垂;如果需要模擬多種類(lèi)型的用戶(hù),則可以指定多個(gè)類(lèi)名伦仍,框架會(huì)根據(jù)每個(gè)Locust類(lèi)的權(quán)重分配模擬用戶(hù)的比例(默認(rèn)權(quán)重為10)结窘。
一個(gè)簡(jiǎn)單示例如下:
from locust import TaskSet, HttpLocust, task, TaskSequence, seq_task, InterruptTaskSet
class HangOutTaskSet(TaskSet):
@task
def hang_out(self):
print("the player is hanging out")
class PlayGameTaskSet(TaskSet):
@task
def play(self):
print("the player is playing game")
class PlayerOwn(HttpLocust):
weight = 10
task_set = HangOutTaskSet
host = "http://www.baidu.com"
min_wait = 10000
max_wait = 10000
class PlayerTwo(HttpLocust):
weight = 90
task_set = PlayGameTaskSet
host = "http://www.baidu.com"
min_wait = 10000
max_wait = 10000
命令行運(yùn)行:locust -f ***.py PlayerOwn PlayerTwo
如果并發(fā)10人,就會(huì)有1人在閑逛充蓝,9人在玩游戲了
2.TaskSet的tasks屬性
從(一)我們知道了一種定義任務(wù)的方式隧枫,就是在TaskSet類(lèi)中定義一個(gè)方法喉磁,并標(biāo)注其為@task;另一個(gè)定義任務(wù)的方式就是使用TaskSet的tasks屬性官脓,這個(gè)屬性值可以是數(shù)組或字典协怒,其中表示的任務(wù)可以是一個(gè)函數(shù),也可以是另一個(gè)TaskSet确买。
如果使用數(shù)組斤讥,其元素可以是元組(callable, int),int值即為該任務(wù)的權(quán)重湾趾。
- 函數(shù)
示例中的tasks = [(play_one, 5), play_two]
與tasks = {play_one: 5, play_two: 1}
是完全等價(jià)的
tasks中的函數(shù)和有注解@task的函數(shù)有同等的地位芭商,都是這個(gè)TaskSet的一個(gè)基本單位。
# 函數(shù)需有一個(gè)參數(shù)表示self
def play_one(self):
print("play_one")
def play_two(self):
print("play_two")
class PlayGameTaskSet(TaskSet):
tasks = [(play_one, 5), play_two]
@task
def play(self):
print("the player is playing game")
class PlayerTwo(HttpLocust):
weight = 90
task_set = PlayGameTaskSet
host = "http://www.baidu.com"
min_wait = 100
max_wait = 100
- 嵌套TaskSet
tasks屬性的元素也可以是另一個(gè)TaskSet搀缠,這種做法就會(huì)形成嵌套的子任務(wù)铛楣。
例如:我們測(cè)試一款游戲,需要每一個(gè)用戶(hù)在大廳閑逛的時(shí)候艺普,有1/10的概率進(jìn)入游戲比賽進(jìn)行另外的操作簸州,比賽結(jié)束退出后繼續(xù)閑逛,示例如下:
class PlayGameTaskSet(TaskSet):
tasks = [play_one, play_two]
@task(5)
def play_game(self):
print("the player is playing game")
@task
def end_game(self):
print("game end")
self.interrupt()
class HangOutTaskSet(TaskSet):
tasks = {PlayGameTaskSet: 1}
@task(9)
def hang_out(self):
print("the player is hanging out")
當(dāng)進(jìn)入嵌套的任務(wù)集執(zhí)行任務(wù)后歧譬,會(huì)根據(jù)嵌套任務(wù)集的任務(wù)權(quán)重執(zhí)行任務(wù)岸浑,除非調(diào)用self.interrupt()
或拋出中斷異常raise InterruptTaskSet
否則將一直在子任務(wù)集中執(zhí)行下去
3.內(nèi)部類(lèi)
還有一種實(shí)現(xiàn)嵌套子任務(wù)的方式是使用內(nèi)部類(lèi),如上訴示例瑰步,等同于:
class HangOutTaskSet(TaskSet):
@task(9)
def hang_out(self):
print("the player is hanging out")
@task
class PlayGameTaskSet(TaskSet):
tasks = [play_one, play_two]
@task(5)
def play_game(self):
print("the player is playing game")
@task
def end_game(self):
print("game end")
self.interrupt()
4.類(lèi)的繼承
如果一個(gè)TaskSet的父類(lèi)是另一個(gè)TaskSet矢洲,那么父類(lèi)的所有任務(wù)會(huì)同樣的成為子類(lèi)的任務(wù)。
5.總結(jié)
在(一)中介紹了框架的幾個(gè)角色缩焦,Locust類(lèi)是創(chuàng)建模擬用戶(hù)的模板读虏,所以如果我們要使用不同的角色進(jìn)行測(cè)試時(shí),就需要給框架提供不同的Locust類(lèi)袁滥。TaskSet類(lèi)是模擬需要執(zhí)行的任務(wù)集盖桥,我覺(jué)得可以這么理解,這是一個(gè)任務(wù)的池子题翻,里面的每個(gè)單位都是一個(gè)任務(wù)揩徊,這個(gè)任務(wù)可以是函數(shù)也可以是另一個(gè)TaskSet,這個(gè)任務(wù)的定義方式有幾個(gè)(當(dāng)前TaskSet通過(guò)@task定義嵌赠,繼承父類(lèi)的任務(wù)靴拱,tasks屬性中一個(gè)元素),但它們都是同等地位的猾普,執(zhí)行的概率與它們的權(quán)重相同,每一次模擬用戶(hù)都會(huì)從這個(gè)池子里挑選任務(wù)進(jìn)行執(zhí)行(直到stop_timeout
或頁(yè)面點(diǎn)擊Stop
)本谜。當(dāng)挑選到一個(gè)類(lèi)型為T(mén)askSet的任務(wù)執(zhí)行時(shí)初家,就進(jìn)入了嵌套的子任務(wù)當(dāng)中,相當(dāng)于到了子任務(wù)的池子里開(kāi)始挑選任務(wù)執(zhí)行(直到調(diào)用self.interrupt()
或拋出中斷異常raise InterruptTaskSet
)。