编写一个Locust文件

Locust文件就是一般的Python文件。唯一的需求就是它至少需要一个继承于Locust的类.

Locust类

Locust类代表一个用户(如果愿意,也可以是一个准备出动的蝗虫)。Locust会为每一个模拟用户生成一个locust类实例。同时会有一些locust类属性被定义。

task_set属性

task_set属性是指向一个定义用户行为的TaskSet类,下面会有详细的介绍。

min_waitmax_wait属性

除了task_set属性,另外一个经常被使用的就是min_waitmax_wait属性。是用于各自以毫秒为单位的最小值和最大值,一个模拟用户将会在每个任务执行时的等待执行的时间间隔。min_waitmax_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_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属性是到要加载目标URL的前缀(如:"http://google.com")。通常情况下,当Locust被启动时,在命令行中是需要通过--host来指定的。如果host属性在locustfile文件中被声明,则在命令行中则不需要使用--host属性来再次声明。

TaskSet

如果Locust类代表一只准备出动的蝗虫,那么你可以说TaskSet类代表蝗虫的大脑。每一个Locust类中必须要包含一个指向TaskSettask_set属性设置。

TaskSet就像它的名字一样,是一个任务集合。这些任务是常规的Python调用,如果我们压力测试一个拍卖网站,便可以做这些操作加载启动页面搜索一些产品竞标

当一个压力测试被启动时,每一个准备的Locust类实例将会开始执行它们的TaskSet。接下来是每一个TaskSet找到它的task并调用它。它将在min_waitmax_wait属性值之间随机等待几毫秒(除非min_waitmax_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列表的调用就是一个<callbale:int>字典。tasks是python调用接收执行task的TaskSet类实例参数。下面是一个极其简单的示例(不会影响任何测试):

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
    • 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 patchoptions方法来生成HTTP请求,用于Locust的数据统计。HttpSession实例在请求间维护cookies,因此可用于登录网站并保存session在请求之间。client可以通过Locust实例的TaskSet实例来关联,因此很容易获取client并在任务中生成HTTP请求。

下面是一个生成GET请求到 /about 路径的示例(在这里,我们可以假设 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统计中算做一次失败。返回假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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,849评论 6 13
  • Locust是什么? Locust 是一个开源负载测试工具。使用 Python 代码定义用户行为,也可以仿真百万个...
    zychen143阅读 7,117评论 1 2
  • 原文地址:RESTful web API文档生成器 问:开发业务模块代码最重要的是什么?答:API接口文档 如果你...
    brucewar阅读 4,868评论 0 51