需构建含Python、pytest及测试依赖的Docker镜像,COPY代码或挂载卷,CMD设为pytest命令,配置网络访问宿主机服务,用--junitxml生成可写路径XML报告。

pytest怎么在Docker容器里直接运行测试用例
不能直接在宿主机上跑 pytest 然后“假装”它在容器里——得让测试进程真正在容器内启动、执行、退出。核心是把测试代码、依赖、pytest 本身都打进镜像,再用 docker run 启动容器并执行命令。
- 镜像里必须安装 Python 和
pytest(推荐用pip install pytest,别依赖系统包管理器,版本难控) - 测试目录要通过
COPY指令复制进镜像,或挂载为卷(开发调试时用-v,CI 中不建议挂载,破坏可重现性) - 入口命令设为
pytest tests/ -v或写成CMD ["pytest", "tests/", "-v"],避免 shell 解析差异(比如/bin/sh -c 'pytest ...'在 Alpine 上可能没sh) - 如果测试读配置文件或连数据库,容器启动时得用
--network或--add-host配置网络可达性,别等报ConnectionRefusedError才回头查
Dockerfile里哪些依赖必须显式声明
很多人只 COPY 代码、RUN pip install -r requirements.txt,但漏掉 pytest 运行时真正需要的底层东西:比如 psutil(某些 fixture 用)、requests(API 测试)、甚至 pytest-xdist(并行)这种非业务依赖。它们不会自动出现在 requirements.txt 里,但 pytest 命令一执行就报 ModuleNotFoundError。
- 单独建一个
requirements-test.txt,放pytest、pytest-cov、responses等测试专用包 - Dockerfile 中分层安装:
RUN pip install -r requirements.txt→RUN pip install -r requirements-test.txt,方便缓存复用 - Alpine 镜像下装
pytest-cov可能失败,因为缺gcc和musl-dev,得提前apk add --no-cache gcc musl-dev - 别在
ENTRYPOINT里做 pip install,构建阶段完成,运行阶段只负责执行
为什么 pytest --junitxml 报错或生成空报告
容器里生成 JUnit XML 是 CI(比如 Jenkins、GitLab CI)识别测试结果的关键,但常因路径、权限、时区问题失败或输出为空。
-
--junitxml=/report.xml的路径必须是容器内存在的可写目录,比如用RUN mkdir -p /reports+--junitxml=/reports/report.xml - 若用
docker run -v $(pwd)/reports:/reports挂载,注意宿主机目录权限(尤其 macOS/Linux 用户组不一致时,容器内 UID 写不了) - 某些 pytest 插件(如
pytest-asyncio)和--junitxml共用时会静默跳过部分测试,加-s看 stdout 输出确认是否真执行了 - XML 文件生成后立刻
cat /reports/report.xml查结构,别只看 exit code —— 成功返回但内容为空很常见
容器内 pytest 无法访问 localhost:3000 怎么办
本地开发时测试常连宿主机起的服务(比如前端 dev server 或 mock API),但在容器里 localhost 指的是容器自己,不是宿主机。
- Linux 下用
host.docker.internal(Docker Desktop 默认支持;Linux 需加--add-host=host.docker.internal:host-gateway) - 更稳的方式是让被测服务也跑在 Docker 网络里,用
docker-compose编排,测试容器通过服务名(如api:3000)访问 - 避免在测试代码里硬编码
http://localhost:3000,改用环境变量BASE_URL,启动容器时用-e BASE_URL=http://host.docker.internal:3000 - 如果服务必须在宿主机跑且端口已暴露,检查宿主机防火墙(尤其是 Windows WSL2 的 iptables 规则)是否拦截了容器发来的请求
事情说清了就结束
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











