关于自定义钩子 —小试牛刀
Locust 事件钩子(Event Hooks)总结
Locust 提供了许多事件钩子,允许你在测试运行时扩展和自定义功能。以下是一些主要的事件钩子及其使用场景和示例:
1. 请求完成事件(Request Completed Event)
使用场景:当每个请求完成后,你可能希望记录请求的结果,或在请求失败时执行一些操作。
示例:
from locust import events
@events.request.add_listener
def my_request_handler(request_type, name, response_time, response_length, response, context, exception, start_time, url, **kwargs):
if exception:
print(f"Request to {name} failed with exception {exception}")
else:
print(f"Successfully made a request to: {name}")
print(f"The response was {response.text}")
解释:在这个示例中,我们为 request
事件添加了一个监听器,用于在请求完成后输出信息。如果请求出现异常,打印异常信息;否则,打印请求成功的信息和响应内容。
2. 测试开始和结束事件(Test Start and Stop Events)
使用场景:在分布式模式下,可能需要在测试开始前和结束后执行一些初始化或清理工作。
示例:
from locust import events
from locust.runners import MasterRunner
@events.test_start.add_listener
def on_test_start(environment, **kwargs):
if not isinstance(environment.runner, MasterRunner):
print("Beginning test setup")
else:
print("Started test from Master node")
@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
if not isinstance(environment.runner, MasterRunner):
print("Cleaning up test data")
else:
print("Stopped test from Master node")
解释:test_start
和 test_stop
事件用于在测试开始和结束时执行操作。这个示例根据当前节点类型(Master 或 Worker)打印相应的信息,并进行初始化或清理操作。
3. 请求上下文(Request Context)
使用场景:你可能需要在请求中传递额外的数据(如用户名),并在监听器中使用这些数据。
示例:
class MyUser(HttpUser):
@task
def t(self):
self.client.post("/login", json={"username": "foo"})
self.client.get("/other_request", context={"username": "foo"})
@events.request.add_listener
def on_request(context, **kwargs):
if context:
print(context["username"])
解释:通过 context
参数可以传递请求数据。在这个示例中,我们在 GET 请求中传递了用户名,并在请求监听器中打印这个用户名。
4. 添加 Web 路由(Adding Web Routes)
使用场景:需要在 Locust 的 Web UI 中添加自定义页面或路由以显示额外的信息。
示例:
from locust import events
@events.init.add_listener
def on_locust_init(environment, **kw):
@environment.web_ui.app.route("/added_page")
def my_added_page():
return "Another page"
解释:通过监听 init
事件,我们可以在 Locust 的 Web UI 中添加一个新的路由 /added_page
,显示额外的页面内容。
5. 运行后台 Greenlet(Run a Background Greenlet)
使用场景:在测试过程中监控失败率并在超过阈值时停止测试。
示例:
import gevent
from locust import events
from locust.runners import STATE_STOPPING, STATE_STOPPED, STATE_CLEANUP, MasterRunner, LocalRunner
import time
def checker(environment):
while not environment.runner.state in [STATE_STOPPING, STATE_STOPPED, STATE_CLEANUP]:
time.sleep(1)
if environment.runner.stats.total.fail_ratio > 0.2:
print(f"fail ratio was {environment.runner.stats.total.fail_ratio}, quitting")
environment.runner.quit()
return
@events.init.add_listener
def on_locust_init(environment, **_kwargs):
if isinstance(environment.runner, MasterRunner) or isinstance(environment.runner, LocalRunner):
gevent.spawn(checker, environment)
解释:这个示例中,checker
函数用于定期检查失败率,如果失败率超过 20%,则停止测试。通过在 init
事件中启动 Greenlet 线程来实现这一点。
6. 自定义命令行参数(Custom Command Line Arguments)
使用场景:在测试运行时需要使用自定义命令行参数进行配置。
示例:
from locust import HttpUser, events, task
@events.init_command_line_parser.add_listener
def _(parser):
parser.add_argument("--my-argument", type=str, env_var="LOCUST_MY_ARGUMENT", default="", help="It's working")
parser.add_argument("--env", choices=["dev", "staging", "prod"], default="dev", help="Environment")
@events.test_start.add_listener
def _(environment, **kw):
print(f"Custom argument supplied: {environment.parsed_options.my_argument}")
class WebsiteUser(HttpUser):
@task
def my_task(self):
print(f"my_argument={self.environment.parsed_options.my_argument}")
解释:通过 init_command_line_parser
事件添加自定义命令行参数,并在 test_start
事件中打印这些参数的值。这个功能允许用户在运行 Locust 时传递和使用自定义参数。
总结
这些事件钩子可以帮助你在 Locust 测试中进行各种扩展和定制。通过合理利用这些钩子,你可以增强测试的功能性和灵活性,满足各种复杂的测试需求。
自定义命令行参数(Custom Command Line Arguments) —武动乾坤
Locust 允许你在命令行中定义自定义参数,这些参数不仅可以在测试脚本中使用,还可以在 Locust 的 Web UI 中显示和编辑。这可以为用户提供更多的配置选项和灵活性。
使用场景
- 测试配置:在测试开始时,根据不同的需求或环境配置测试参数。
- Web UI 集成:在 Locust 的 Web UI 中显示和编辑自定义参数,方便测试人员进行配置调整。
示例代码
以下是如何定义和使用自定义命令行参数,并在 Locust 的 Web UI 中显示这些参数的示例:
from locust import HttpUser, events, task
# 自定义命令行参数
@events.init_command_line_parser.add_listener
def _(parser):
# 添加一个普通参数
parser.add_argument("--my-argument", type=str, env_var="LOCUST_MY_ARGUMENT", default="", help="A custom argument")
# 添加一个具有选项的下拉菜单参数
parser.add_argument("--env", choices=["dev", "staging", "prod"], default="dev", help="Environment")
# 添加一个在 Web UI 中不可见的参数
parser.add_argument("--my-ui-invisible-argument", include_in_web_ui=False, default="I am invisible")
# 添加一个在 Web UI 中作为密码输入的参数
parser.add_argument("--my-ui-password-argument", is_secret=True, default="I am a secret")
# 处理测试开始时的参数
@events.test_start.add_listener
def _(environment, **kw):
print(f"Custom argument supplied: {environment.parsed_options.my_argument}")
class WebsiteUser(HttpUser):
@task
def my_task(self):
# 使用自定义命令行参数
print(f"my_argument={self.environment.parsed_options.my_argument}")
print(f"my_ui_invisible_argument={self.environment.parsed_options.my_ui_invisible_argument}")
参数说明
-
普通参数:
parser.add_argument("--my-argument", type=str, env_var="LOCUST_MY_ARGUMENT", default="", help="A custom argument")
这个参数可以从命令行传递,例如
--my-argument=value
,并可以通过环境变量LOCUST_MY_ARGUMENT
设置。 -
选项参数:
parser.add_argument("--env", choices=["dev", "staging", "prod"], default="dev", help="Environment")
这个参数会在 Web UI 中显示为一个下拉菜单,用户可以选择不同的环境配置。
-
不可见参数:
parser.add_argument("--my-ui-invisible-argument", include_in_web_ui=False, default="I am invisible")
这个参数在 Web UI 中不会显示,适用于需要隐藏的配置项。
-
密码参数:
parser.add_argument("--my-ui-password-argument", is_secret=True, default="I am a secret")
这个参数在 Web UI 中会显示为密码输入框,适用于需要保密的配置项。
在 Web UI 中使用自定义参数
在 Web UI 中,自定义参数将显示在测试设置页面的“设置”部分。你可以根据需要调整这些参数,以便在测试过程中进行不同的配置。参数的显示方式和可编辑性取决于你在定义参数时的配置(例如,是否设置了 include_in_web_ui=False
或 is_secret=True
)。
通过自定义命令行参数,你可以更灵活地配置和管理 Locust 的测试,满足不同场景下的需求。
测试数据管理(Test Data Management) —完美世界
在 Locust 中,测试数据的管理是一个重要的方面,因为测试通常需要处理大量的数据。这些数据可以通过不同的方式引入到测试中。Locust 通过事件提供了精细的控制,以便在测试执行过程中获取和释放测试数据。
使用场景
- 动态数据加载:在测试运行时,根据需要动态加载数据,例如从数据库或 API。
- 数据清理:在测试结束时,释放或清理测试数据,以确保测试环境的干净和一致性。
- 性能测试:对于需要大量数据的性能测试,动态数据管理可以帮助模拟更真实的负载场景。
示例代码
以下是一个示例,演示了如何在 Locust 中管理测试数据:
import os
import json
import random
from locust import HttpUser, task, events
# 全局变量用于存储测试数据
test_data = []
def load_test_data():
# 模拟从文件或数据库加载数据
global test_data
with open("test_data.json") as f:
test_data = json.load(f)
def release_test_data():
global test_data
test_data = []
@events.test_start.add_listener
def on_test_start(environment, **kwargs):
load_test_data()
@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
release_test_data()
class WebsiteUser(HttpUser):
@task
def my_task(self):
if not test_data:
print("No test data available")
return
# 从测试数据中随机选择一项
data = random.choice(test_data)
# 使用测试数据进行请求
self.client.post("/api/endpoint", json=data)
示例说明
-
数据加载:
def load_test_data(): with open("test_data.json") as f: global test_data test_data = json.load(f)
在
on_test_start
事件中调用load_test_data
函数,从文件或数据库中加载测试数据。这是在测试开始时执行的操作。 -
数据释放:
def release_test_data(): global test_data test_data = []
在
on_test_stop
事件中调用release_test_data
函数,释放测试数据,以便测试结束后清理数据。 -
使用数据:
class WebsiteUser(HttpUser): @task def my_task(self): if not test_data: print("No test data available") return data = random.choice(test_data) self.client.post("/api/endpoint", json=data)
在
WebsiteUser
类的my_task
方法中,使用加载的测试数据进行 HTTP 请求。如果没有数据可用,任务将不会执行。
关键点
- 数据加载和释放:通过
events.test_start
和events.test_stop
事件管理数据的加载和释放,确保测试前后数据的正确性。 - 数据使用:在任务中使用测试数据,以便在负载测试中模拟真实的场景。
通过以上方法,你可以有效地管理 Locust 中的测试数据,实现更灵活和高效的测试策略。