360彩票网站

实验:利用Locust完成测试登录
作者:强官涛   类型:Python开发    类别:实验   日期:2019-04-04    阅读:2107 次   消耗积分:0 分


1.捕获请求

性能测试是基于接口测试的,对于蜗牛进销存系统的登录功能来说,我们先要分析登录请求和响应的数据,用代码去模拟实现,并最终利用Locust的工具去施加负载。这里继续使用HttpWatch工具来捕获登录请求进行分析。

 

(1)打开蜗牛进销存系统和HttpWatch,点击“Record”按钮开始录制,在蜗牛进销存系统上输入正确的用户名和密码进行登录操作。


20190404_161844_514.png


(2)很容易想到,登录是一个向服务器提交数据的操作,所以选择相应的POST请求来进行分析。


20190404_161859_556.png


(3)点击HttpWatch中的“Headers”选项,查看请求和响应的头部信息,这里我们最关注的无非是请求头部的第一行内容:请求的类型和请求的地址。


20190404_161921_552.png


(4)既然是POST请求,那当然有请求正文,点击“POST Data”选项,可以看到请求正文的三个参数,恰好对应了界面登录时的用户名、密码、验证码三个字段,如图-xx。注意这里依然使用的预先设置好的万能验证码来绕过验证。


20190404_161943_725.png


(5)点击“Content”选项,显示响应内容为“login-pass”,从字面意思就能理解,这是登录成功时服务器返回的正文,那么届时去统计登录是否成功时,就要借助于此。


20190404_162002_793.png


经过上述分析,我们对编写脚本也应用有了基本的雏形。但性能测试知识告诉我们需要“尽可能的模拟真实场景”,那么在实现完整脚本前我们还需要做一些工作。

 

2.循环用户


前面我们一直使用admin进行登录操作,但实际的场景往往是多个用户使用不同的账户进行登录,那么这里我们需要使用到循环获取用户。顺便说一点,这里的循环用户类似于LoadRunnder中的参数化的功能,只是Locust本身并没有这个概念,所以笔者称其为“循环”获取数据。


from locust import TaskSet, task, HttpLocust

class UserBehavior(TaskSet):

    def on_start(self):

        self.index = 0

        self.loginData = ['lm', 'liuchan', 'dy', 'wangwu', 'admin']

    @task

    def testUser(self):

        print("---- index :" + str(self.index))

        print("---- data :" + self.loginData[self.index])

        self.index = (self.index + 1) % len(self.loginData)

class WebsiteUser(HttpLocust):

    task_set = UserBehavior

    min_wait = 1000

    max_wait = 3000


在UserBehavior类中定义了一个on_start方法,当Locust运行时,首先会调用它,然后再去执行其他被@task修饰的任务,我们可以利用它来初始化测试数据,有些类似于构造方法的作用。on_start方法内声明了self.index用于保存下标,而列表self.loginData则保存需要登录的所有用户。


这里仅仅为了测试效果,所有在testUser方法中并没有发送任何请求,而是输出了当前的下标和对应的用户名,在testUser方法的最后,我们将self.index的值加1,目的是使下标的值在每次执行任务时都有变化,对len(self.loginData)取余数则是为了让self.index的值不会越界,由于self.loginData的长度是5,所以self.index的值始终都在0到4的范围内循环。

打开控制台cmd,成功启动Locust。


locust -f TestLoop.py --host=http://localhost

[2018-06-01 23:36:33,573] FS6V6WNJF0VQTT3/INFO/locust.main: Starting web monitor

 at *:8089

[2018-06-01 23:36:33,583] FS6V6WNJF0VQTT3/INFO/locust.main: Starting Locust 0.8


打开浏览器,输入:http://localhost:8089,为了方便观察,这里我们设置模拟用户数和用户产生率都为1,则始终只会有一个用户执行任务,最后点击“Start swarming”开始运行。

20190404_162049_245.png


返回到控制台,观察输出的信息,可以看到下标的值在不断的循环,每次执行任务都输出了不同的用户,达到了循环的目的。


[2018-06-01 23:42:39,135] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :0

[2018-06-01 23:42:39,135] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:39,135] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :lm

[2018-06-01 23:42:39,136] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:41,036] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :1

[2018-06-01 23:42:41,036] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:41,037] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :liuchan

[2018-06-01 23:42:41,037] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:42,877] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :2

[2018-06-01 23:42:42,878] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:42,880] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :dy

[2018-06-01 23:42:42,882] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:45,696] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :3

[2018-06-01 23:42:45,697] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:45,699] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :wangwu

[2018-06-01 23:42:45,701] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:47,911] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :4

[2018-06-01 23:42:47,912] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:47,913] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :admin

[2018-06-01 23:42:47,915] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:49,779] FS6V6WNJF0VQTT3/INFO/stdout: ---- index :0

[2018-06-01 23:42:49,780] FS6V6WNJF0VQTT3/INFO/stdout:

[2018-06-01 23:42:49,782] FS6V6WNJF0VQTT3/INFO/stdout: ---- data :lm

[2018-06-01 23:42:49,784] FS6V6WNJF0VQTT3/INFO/stdout:


3.检查点


为了理解检查点,下面我们先写段代码来做一个试验。代码很简单,doLogin的任务里构造了请求正文的参数,我们故意设置一个错误的密码123456,接着对登录的地址发送POST请求,并添加正文body。


from locust import HttpLocust,TaskSet,task

class UserBehavior(TaskSet):

    @task

    def doLogin(self):

        body = {'username':'admin','password':'123456','verifycode':'0000'}

        self.client.post("/WoniuSales/user/login",body)

class WebSite(HttpLocust):

    task_set = UserBehavior

    min_wait = 1000

    max_wait = 3000


启动Locust,在Web界面上运行测试,运行一段时间查看统计图表,有趣的是当一直发送错误的用户名和密码时,并没有得到任何失败的信息,FAILURES始终是0%且#fails的个数也为0,,这是为什么呢?


20190404_162104_733.png


细心的读者或许已经发现,每次请求发送后,并没有对响应的正文进行判断,所以Locust默认都是成功。由于登录成功时,响应的正文内容是“login-pass”,那么很容易设计以下代码段。


    @task

def doLogin(self):

    body = {'username':'admin','password':'123456','verifycode':'0000'}

     res = self.client.post("/WoniuSales/user/login",body)

     if 'login-pass' in res.text:

         print('pass')

     else:

             print('fail')


事实上,虽然对响应的结果进行了判断,并输出了“pass”或“fail”,但这并不能让Locust统计到,图表中依然不会显示失败。因为这里仅仅是在对控制台输出一个信息而已,这和输出“a”或者“b”没有本质区别,而这些信息也不会和Locust产生任何关联。


通过以上的试验,想必读者已经能够体会为什么需要检查点了。在实施性能测试时,我们会把成功率作为一个重要的分析指标,而成功率的统计则依赖检查点的判断。


from locust import HttpLocust,TaskSet,task

class UserBehavior(TaskSet):

    @task

    def doLogin(self):

        body = {'username':'admin','password':'123456','verifycode':'0000'}

        res = self.client.post("/WoniuSales/user/login", body, catch_response= True)

        if 'login-pass' in res.text:

            res.success()

        else:

            res.failure("Login Fail.")

class WebSite(HttpLocust):

    task_set = UserBehavior

    min_wait = 1000

    max_wait = 3000


Locust中,检查点的使用需要请求时的参数catch_response结合success或failure方法。在请求中设置catch_response为true,则表示该响应是允许捕获的,这时就可以响应中使用success或failure方法来标注成功或失败的状态,并被Locust统计到结果的图表中。


执行后统计图表如下,由于登录账户的信息错误,所有请求均被统计为失败,检查点设置成功。


20190404_162119_750.png


4.思考时间


实际用户在对系统进行操作时,肯定不可能一直保持同一频率,操作之间往往间隔的时间都不相同,那么我们可以设置一个随机的等待时间,也叫做思考时间。


from locust import HttpLocust,TaskSet,task

class WebSite(HttpLocust):

    task_set = UserBehavior

    min_wait = 1000

    max_wait = 3000


前面已经提及过,min_wait和max_wait为一个用户在执行任务期间的最小和最大间隔时间,在性能测试中,我们往往需要通过一些市场数据和经验来设置一个合理的范围。

 

5.脚本整合

下面我们将以上的知识点全部整合到一个登录脚本中。


from locust import HttpLocust,TaskSet,task

class UserBehavior(TaskSet):

    def on_start(self):

        self.index = 0

        self.loginData = [['lm','aaa'] ,['liuchan','LiuC456'],\

                          ['dy','DY123'],['wangwu','ww123'], ['admin','admin123']]

    @task

    def doLogin(self):

        body = {'username':self.loginData[self.index][0],\

                'password':self.loginData[self.index][1],'verifycode':'0000'}

        res = self.client.post("/WoniuSales/user/login", body, catch_response= True)

        if 'login-pass' in res.text:

            res.success()

        else:

            res.failure("Login Fail.")

        self.index = (self.index + 1) % len(self.loginData)

class WebSite(HttpLocust):

    task_set = UserBehavior

    min_wait = 1000

    max_wait = 3000


在on_start方法中,将5个账户用嵌套列表进行存储,每个子列表为一组用户名和密码。doLogin方法中,构造请求参数的字典时,把每次获取到的字列表的第一个值与username构造成一对键值对,把获取到的子列表的第二个值与password构造成另一个键值对;然后发送请求,并设置检查点;最后将self.index的值进行循环变化。


为了让读者看到效果,这里设置虚拟用户数为100,每秒产生用户数为10,并且代码中为第一个用户的lm设置了错误的密码aaa,其他用户信息均正确。


20190404_162138_007.png


运行一段时间后,用户数达到100,正确的请求数为8268,失败的请求数为2064,失败的比例恰好为20%,和预期的设想符合。另外统计数据里还展示了最小、最大、平均、中间值所对应的响应时间,每秒处理得请求数为39.2,从这些方面来看,此次测试的结果是较为良好的。




为了答谢大家对蜗牛学院的支持,蜗牛学院将会定期对大家免费发放干货,敬请关注蜗牛学院的官方微信。


20190320_095757_834.jpg





版权所有,转载本站文章请注明出处:蜗牛学院在线课堂, http://quangtruong.net/note/287
上一篇: 访谈:转行IT一年后,他的薪资从5K涨到了9.5K!
下一篇: 实验:利用Locust测试销售出库
提示:登录后添加有效评论可享受积分哦!