在调试器中运行测试

在开发测试时,在调试器中运行 Locust 非常有用。你可以检查特定的响应,或查看一些用户实例变量。

但是,调试器有时会遇到复杂的 gevent 应用程序(如 Locust)的问题,并且框架本身有很多内容,可能并不是你感兴趣的。为了简化这一过程,Locust 提供了一个名为 run_single_user 的方法:

from locust import HttpUser, run_single_user, task


class QuickstartUser(HttpUser):
    host = "http://localhost"

    @task
    def hello_world(self):
        with self.client.get("/hello", catch_response=True) as resp:
            pass  # 你可以在这里设置断点来分析 resp 对象


# 如果直接启动,如 "python3 debugging.py",而不是 "locust -f debugging.py"
if __name__ == "__main__":
    run_single_user(QuickstartUser)

它会隐式地为请求事件注册一个事件处理程序,以打印每个请求的统计信息:

type    name                                           resp_ms exception
GET     /hello                                         38      ConnectionRefusedError(61, 'Connection refused')
GET     /hello                                         4       ConnectionRefusedError(61, 'Connection refused')

你可以通过为 run_single_user 指定参数来配置打印内容。

确保在调试器设置中启用了 gevent。

使用 Vscode 调试 Locust

在 VS Code 中调试 Locust 非常简单:

  • 设置断点

  • 选择一个 Python 文件或场景(例如 examples/basic.py

  • 确保 Poetry 虚拟环境被正确检测(右下角)

  • 打开调试操作,使用 launch.json。你将有多个选择:调试 Python 文件、使用 WebUI 或以无头模式调试

  • 你可以使用快捷键 F5 重新运行。

VS Code 的 launch.json 配置如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Run current file",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "gevent": true
        },
        {
            "name": "Run current locust scenario headless",
            "type": "python",
            "request": "launch",
            "module": "locust",
            "args": [
                "-f",
                "${file}",
                "--headless",
                "--users=5"
            ],
            "console": "integratedTerminal",
            "gevent": true
        },
        {
            "name": "Run current locust scenario, autostart",
            "type": "python",
            "request": "launch",
            "module": "locust",
            "args": [
                "-f",
                "${file}",
                "--users=5",
                "--autostart",
                "--print-stats",
                "-L=ERROR"
            ],
            "console": "integratedTerminal",
            "gevent": true
        }
    ]
}

如果你想运行整个 Locust 运行时(包括 ramp-up、命令行解析等),你也可以这样做:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Locust: 5 users, with specific config file",
            "type": "python",
            "request": "launch",
            "module": "locust",
            "args": [
                "-f",
                "${file}",
                "--headless",
                "--users=5",
                "--config=${fileDirname}/../locust.conf"
            ],
            "console": "integratedTerminal",
            "gevent": true
        }
    ]
}

在 PyCharm 中也有类似的设置。

VS Code/pydev 可能会给出以下警告:

sys.settrace() should not be used when the debugger is being used

这个警告可以安全地忽略(如果你知道如何解决它,请告诉我们)。

你可以多次执行 run_single_user,如 debugging_advanced.py 中所示。

打印 HTTP 通信

有时,理解为什么 Locust 中的 HTTP 请求失败,而在常规浏览器/其他应用程序中却能正常工作,可能会很困难。以下是如何详细检查通信的步骤:

对于 HttpUser(使用 python-requests):

# 在你的 locustfile 的顶部(或者在你想要跟踪的请求之前)加入以下代码:

import logging
from http.client import HTTPConnection

HTTPConnection.debuglevel = 1
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

对于 FastHttpUser(使用 geventhttpclient):

import sys
...

class MyUser(FastHttpUser):
    @task
    def t(self):
        self.client.get("http://example.com/", debug_stream=sys.stderr)

示例输出(对于 FastHttpUser):

REQUEST: http://example.com/
GET / HTTP/1.1
user-agent: python/gevent-http-client-1.5.3
accept-encoding: gzip, deflate
host: example.com

RESPONSE: HTTP/1.1 200
Content-Encoding: gzip
Accept-Ranges: bytes
Age: 460461
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Fri, 12 Aug 2022 09:20:07 GMT
Etag: "3147526947+ident"
Expires: Fri, 19 Aug 2022 09:20:07 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (nyb/1D20)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 648

<!doctype html>
<html>
<head>
...

当然,你也可以在进行完整负载测试时使用这些方法,但输出可能会非常庞大 :)