小孙同学

导航

 

一、关联

  在某些请求中,需要携带之前从Server端返回的参数,因此在构造请求时需要先从之前的Response中提取出所需的参数。

  下面的示例代码中,用户登录后服务器返回的httptoken的值作为下个任务接口请求的请求头参数,实现了前后接口的关联。

from locust import HttpUser, task, SequentialTaskSet
import hashlib
import queue


class UserBehavior(SequentialTaskSet):
    token = None

    def on_start(self):
        print("--on_start--")

    def on_stop(self):
        print("--on_stop--")

    @task(1)
    def login(self):
        url1 = "http://xx"
        url2 = "http://xx"
        headers1 = {'Content-Type': 'application/json;charset=UTF-8','ptype': '1'}
        headers2 = {'Content-Type': 'application/x-www-form-urlencoded'}
        # request_params = {"codeVerificationType": "1", "phoneNumber": '12345678988'}
        # res_get = requests.get(url, params=request_params, headers=headers)
        # print(res_get.text)
        try:
            # 从队列中取出数据
            data = eval(self.user.user_data_queue.get_nowait())
            print("测试数据:%s" % data)
            payload = {
                "codeVerificationType": "1",
                "phoneNumber": data['phoneNumber']
            }
            res = self.client.get(url1, params=payload, headers=headers1)
            print(res.text)
            hl = hashlib.md5()
            hl.update(str(data['phoneNumber']).encode(encoding='utf-8'))
            code = hl.hexdigest()
            print("手机号加密后:%s" % code)
            par_data = {"channel": 'cocos',
                        "deviceId": None,
                        "deviceType": None,
                        "uniqueId": None,
                        "loginType": 1,
                        "phoneType": 1,
                        "userIdentity": code,
                        "userType": 1,
                        "verificationCode": '123456',
                        "version": '0.9',
                        "versionName": '0.9',
                        "accessToken": None,
                        "token": None
                        }
            res_post = self.client.post(url2, data=par_data, headers=headers2)
            self.token = res_post.json()["result"]["httpToken"]
            print("token:",self.token)
            # print(code)
            print(res_post.text)

            # return self.token
        # 使用get_nowait()方法,取不到数据,就进入这里
        except queue.Empty:
            print("测试数据已用完,结束!")
            exit(0)
        # print("获取的token是:", token)
        # return token

    @task(1)
    def join_room(self):
        headers = {'Content-Type': 'application/json;charset=UTF-8', 'ptype': '1','token': self.token}
        url = "http://xx"
        res_post = self.client.post(url, headers=headers)
        print("加入房间成功:",res_post.text)
        print("*" * 50)


class WebsiteUser(HttpUser):
    host = "http://xx"
    tasks = [UserBehavior]
    # 创建队列,先进先出
    user_data_queue = queue.Queue()
    # 循环加入队列
    for index in range(16000000020, 16000000025):
        data = '''{
            "phoneNumber":"%d"
        }'''% index
        user_data_queue.put_nowait(data.replace(' ', '').replace('\n', ''))
    max_wait = 3000
    min_wait = 1000


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

 

二、参数化

  方式1:循环取数据,数据可重复使用

  所有并发虚拟用户共享同一份测试数据,各虚拟用户在数据列表中循环取值。
  例如,模拟10个用户并发请求网页,总共有4个URL地址,每个虚拟用户都会依次循环加载这4个URL地址。

from locust import SequentialTaskSet, task, HttpUser,events
from gevent._semaphore import Semaphore
all_locusts_spawned = Semaphore()
all_locusts_spawned.acquire()


def on_hatch_complete(**kwargs):
    all_locusts_spawned.release()
# events.on_hatch_complete += on_hatch_complete
events.spawning_complete.add_listener(on_hatch_complete)


class UserBehavior(SequentialTaskSet):
    index = 0
    #
    def on_start(self):
        all_locusts_spawned.wait()

    @task
    def test_visit(self):
        all_locusts_spawned.wait()
        url = self.user.share_data[self.index]
        self.index = (self.index + 1) % len(self.user.share_data)
        with self.client.get(url,catch_response=True) as response:
            if response.status_code == 200:
                response.success()
            else:
                response.failure("查询失败")
        print('visit url: %s' % url)



class WebsiteUser(HttpUser):
    host = "https://www.baidu.com"
    tasks = [UserBehavior]
    share_data = ['https://www.baidu.com/',
                  'https://www.baidu.com/s?wd=1',
                  'https://www.baidu.com/s?wd=2',
                  'https://www.baidu.com/s?wd=3',
                  'https://www.baidu.com/s?wd=4']
    min_wait = 100
    max_wait = 300


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

  方式2:保证并发测试数据唯一性,不循环取数据,使用队列的方法。

  所有并发虚拟用户共享同一份测试数据,并且保证虚拟用户使用的数据不重复。
  例如,模拟10用户并发注册账号,总共有100个账号,要求注册账号不重复,注册完毕后自动结束测试。

from locust import TaskSet, task, HttpUser
import queue

class UserBehavior(TaskSet):

    @task
    def test_register(self):
        try:
            data = self.user.user_data_queue.get()
        except queue.Empty:
            print('account data run out, test ended.')
            exit(0)

        print('register with user: {}, pwd: {}'\
            .format(data['username'], data['password']))
        payload = {
            'username': data['username'],
            'password': data['password']
        }
        res = self.client.post('/register', data=payload)
        print("用户%s:" % data['username'] + res.text)

class WebsiteUser(HttpUser):
    host = 'https://debugtalk.com'
    tasks = [UserBehavior]

    user_data_queue = queue.Queue()
    for index in range(100):
        data = {
            "username": "test%04d" % index,
            "password": "pwd%04d" % index,
            "email": "test%04d@debugtalk.test" % index,
            "phone": "186%08d" % index,
        }
        user_data_queue.put_nowait(data)

    min_wait = 100
    max_wait = 300


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

  方法3:保证并发数据的唯一性,循环取数据,使用队列方法,每次使用完数据后再放入到队列中。

  所有并发虚拟用户共享同一份测试数据,保证并发虚拟用户使用的数据不重复,并且数据可循环重复使用。
  例如,模拟10用户并发登录账号,总共有100个账号,要求并发登录账号不相同,但数据可循环使用。

  该种场景的实现方式与方法2场景基本相同,唯一的差异在于,每次使用完数据后,需要再将数据放入队列中。

  

from locust import TaskSet, task, HttpUser
import queue

class UserBehavior(TaskSet):

    @task
    def test_register(self):
        try:
            data = self.user.user_data_queue.get()
        except queue.Empty:
            print('account data run out, test ended.')
            exit(0)

        print('register with user: {}, pwd: {}'\
            .format(data['username'], data['password']))
        payload = {
            'username': data['username'],
            'password': data['password']
        }
        self.client.post('/register', data=payload)
        self.user.user_data_queue.put_nowait(data)


class WebsiteUser(HttpUser):
    host = 'https://debugtalk.com'
    tasks = [UserBehavior]
    user_data_queue = queue.Queue()
    for index in range(100):
        data = {
            "username": "test%04d" % index,
            "password": "pwd%04d" % index,
            "email": "test%04d@debugtalk.test" % index,
            "phone": "186%08d" % index,
        }
        user_data_queue.put_nowait(data)

    min_wait = 100
    max_wait = 300


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

三、检查点

  假设接口响应状态码正常结果是200,具体响应结果判断可根据实际返回结果自定义,以下示例以状态码判断为例。

  locust 在请求方法中设置 catch_response = True
  调用 response.success() 或 response.failure() 在结果中标注成功或失败

  

from locust import SequentialTaskSet, task, HttpUser,events
from gevent._semaphore import Semaphore
all_locusts_spawned = Semaphore()
all_locusts_spawned.acquire()


def on_hatch_complete(**kwargs):
    all_locusts_spawned.release()
# events.on_hatch_complete += on_hatch_complete
events.spawning_complete.add_listener(on_hatch_complete)


class UserBehavior(SequentialTaskSet):
    index = 0
    #
    def on_start(self):
        all_locusts_spawned.wait()

    @task
    def test_visit(self):
        all_locusts_spawned.wait()
        url = self.user.share_data[self.index]
        self.index = (self.index + 1) % len(self.user.share_data)
        with self.client.get(url,catch_response=True) as response:
            if response.status_code == 200:
                response.success()
            else:
                response.failure("查询失败")
        print('visit url: %s' % url)


class WebsiteUser(HttpUser):
    host = "https://www.baidu.com"
    tasks = [UserBehavior]
    share_data = ['https://www.baidu.com/',
                  'https://www.baidu.com/s?wd=1',
                  'https://www.baidu.com/s?wd=2',
                  'https://www.baidu.com/s?wd=3',
                  'https://www.baidu.com/s?wd=4']
    min_wait = 100
    max_wait = 300


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

 

四、集合点

from locust import SequentialTaskSet, task, HttpUser,events
from gevent._semaphore import Semaphore
all_locusts_spawned = Semaphore()
all_locusts_spawned.acquire()


def on_hatch_complete(**kwargs):
    all_locusts_spawned.release() # 创建钩子方法
# events.on_hatch_complete += on_hatch_complete
# 挂在到locust钩子函数(所有的Locust示例产生完成时触发)
events.spawning_complete.add_listener(on_hatch_complete)


class UserBehavior(SequentialTaskSet):
    index = 0
    # 限制在所有用户准备完成前处于等待状态
    def on_start(self):
        all_locusts_spawned.wait()

    @task
    def test_visit(self):
        all_locusts_spawned.wait() # 限制在所有用户准备完成前处于等待状态
        url = self.user.share_data[self.index]
        self.index = (self.index + 1) % len(self.user.share_data)
        with self.client.get(url,catch_response=True) as response:
            if response.status_code == 200:
                response.success()
            else:
                response.failure("查询失败")
        print('visit url: %s' % url)


class WebsiteUser(HttpUser):
    host = "https://www.baidu.com"
    tasks = [UserBehavior]
    share_data = ['https://www.baidu.com/',
                  'https://www.baidu.com/s?wd=1',
                  'https://www.baidu.com/s?wd=2',
                  'https://www.baidu.com/s?wd=3',
                  'https://www.baidu.com/s?wd=4']
    min_wait = 100
    max_wait = 300


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

 

posted on 2021-04-10 21:58  是孙同学啊  阅读(389)  评论(0)    收藏  举报