pytest-xdist需单独安装,未安装会导致importerror;-n auto按cpu核数减1启动进程,但受测试间资源冲突限制;应避免共享文件、端口、数据库,改用临时路径、内存sqlite或随机后缀;–dist=loadgroup按类或标记分组调度,适合有状态依赖的测试。

pytest-xdist 启动就报 ImportError: No module named 'xdist'
这是环境没装对,不是插件没启用。pytest-xdist 是独立包,不随 pytest 自带,必须显式安装。
- 用
pip install pytest-xdist,别只装pytest - 如果用虚拟环境,确认当前 shell 激活的是目标环境(
which python和which pytest要一致) - 某些旧项目用了
setup.py或requirements.txt,但漏了pytest-xdist—— 它不会被自动推导依赖
加了 -n auto 却只跑 1 个进程
-n auto 不是“尽量多开”,而是按 os.cpu_count() 算出逻辑核数后减 1(留一个给主控),但实际能用多少还取决于测试本身是否真能并行。
- 若测试里有全局锁、共享文件写入、
time.sleep()或硬编码的端口(如8000),pytest-xdist 会退化为串行执行(或直接失败) - macos 上
os.cpu_count()返回的是逻辑核数,但 M 系列芯片上部分 Python 版本存在识别偏差,可改用-n 2或-n 4显式指定 - CI 环境(如 github Actions)默认只分配 2 核,
-n auto就是 1,得看 CI 配置再调
测试间相互干扰:数据库连接冲突、临时文件覆盖
pytest-xdist 把测试分发到多个子进程中,它们默认共用同一工作目录和环境变量,但不共享内存 —— 所以文件/端口/数据库这类外部资源极易撞车。
- 避免硬编码路径:
/tmp/test.db改成tempfile.mktemp(prefix=f"test_{os.getpid()}_") - 数据库用内存 SQLite(
sqlite:///file::memory:)或每个 worker 加随机后缀:sqlite:///test_{worker_id}.db,其中worker_id可通过os.environ.get("PYTEST_XDIST_WORKER")获取 - http 测试别固定端口,用
0让系统自动分配:http.server.HTTPServer(("", 0), handler)
--dist=loadgroup 和 --dist=load 差在哪
区别在分组粒度:load 按单个 test function 分发,loadgroup 按 class 或 pytest.mark 分组后整体调度 —— 后者更适合有内部状态依赖的测试集。
立即学习“Python免费学习笔记(深入)”;
- 如果某
TestAPIclass 里多个方法共用一个登录 Token,用--dist=load可能把 login 和 use_token 拆到不同进程,直接失败;换成--dist=loadgroup就能保序 -
--dist=loadgroup需配合@pytest.mark.xdist_group(name="api")使用,否则默认按 class 名分组 - 组太大(比如整个
TestIntegration有 50 个方法)会导致某个 worker 负载过重,反而拖慢总耗时
多进程下 fixture 的初始化时机、日志混杂、覆盖率统计失效,这些都不是配置开关能一键解决的。得先看清测试本身有没有隐式共享状态——这才是并行真正的门槛。