pytest会误执行locustfile.py,因其导入时触发locust模块级代码(如httpuser定义),导致attributeerror、importerror或事件循环冲突;推荐通过重命名+pytest.ini排除、if name=="main"包裹入口、或# pytest: no-inject注释+--ignore隔离。

pytest 和 Locust 脚本放一起时,pytest 会把 locustfile.py 当成普通测试用例执行,报错、跳过、甚至干扰压测环境初始化——这不是配置问题,是 pytest 的默认发现机制直接撞上了 Locust 的命名惯例。
为什么 pytest 会误执行 locustfile.py
pytest 默认扫描所有以 test_ 开头或以 _test.py 结尾的文件,但实际行为更宽泛:只要文件名含 test 或匹配 python_files 配置(默认包括 *test.py),就会尝试导入。而 locustfile.py 虽不满足命名规则,一旦它被 import(比如在 conftest.py 中做了 from performance.locustfile import …),pytest 就可能触发其模块级代码(如 HttpUser 类定义、全局变量初始化),导致:
– 报 AttributeError: 'module' object has no attribute 'client'(Locust 未启动,self.client 不存在)
– 报 ImportError(Locust 依赖未就绪,如 gevent 冲突)
– pytest 启动失败或挂起(因 Locust 启动了事件循环)
三种可靠隔离方式(按推荐顺序)
核心原则:让 pytest「看不见」Locust 脚本,或让它「不执行」Locust 逻辑。
- 重命名 + 排除:把
locustfile.py改为perf_load.py(去掉locust关键字避免被自动识别),并在pytest.ini中显式排除:[tool:pytest] python_files = test_*.py python_classes = Test* python_functions = test_* norecursedirs = .git __pycache__ performance
或更精准地:norecursedirs = performance
(如果整个目录只放 Locust 脚本) - 用
if __name__ == "__main__":包裹 Locust 入口:确保 Locust 相关逻辑(如HttpUser定义、locust -f启动逻辑)只在直接运行时生效,pytest 导入时不会触发:from locust import HttpUser, task, between <p>class SalaryUser(HttpUser): host = "<a href="https://www.php.cn/link/a1668ffc4a96b650355d86b7d70fe59a">https://www.php.cn/link/a1668ffc4a96b650355d86b7d70fe59a</a>" wait_time = between(2, 5)</p><pre class="brush:python;toolbar:false;">@task def pay(self): self.client.post("/api/v1/salary/pay", json={"emp_id": "E001"})? 这行必须有,且不能放在模块顶层逻辑里
if name == "main": import os os.system("locust -f perf_load.py")
- 禁用 pytest 对特定文件的收集:在
perf_load.py顶部加注释:# pytest: no-inject from locust import HttpUser, task, between # ... rest of locust code
并在pytest.ini中启用该标记:markers = no-inject: skip this file during collection然后用--ignore=performance/perf_load.py启动 pytest(CI 场景下最稳)
host 参数与 pytest fixture 的冲突点
Locust 的 host 是请求目标地址,而 pytest 的 host fixture(如来自 pytest-asyncio 或自定义)容易同名覆盖。常见现象:
– pytest 报 fixture 'host' not found(因 Locust 类里定义了 host = "...",pytest 误认为是 fixture 声明)
– Locust 启动后请求发到 http://localhost:8089(即 Locust Web UI 地址)而非真实服务
- Locust 的
host必须定义在HttpUser子类中,不能写成模块级变量(否则会被 pytest 当作 fixture 注册) - 避免在
conftest.py或测试文件中定义名为host的 fixture;改用base_url、api_host等明确前缀 - 若需动态 host(如多环境切换),不要用 pytest config value 覆盖
HttpUser.host,而应在on_start()中设置:def on_start(self): self.host = self.environment.parsed_options.host or "https://default.example.com"并通过locust -f xxx.py --host https://staging.example.com传参
真正麻烦的不是写错一行代码,而是 Locust 脚本被 pytest 悄悄加载又没报错——它可能静默跳过任务类、漏初始化 client、甚至让后续的数据库清理 fixture 失效。所以第一反应不该是调参数,而是确认 pytest --collect-only 输出里有没有出现 performance/ 下的任何节点。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











