如何用Pytest自动为不同测试匹配对应Conda环境?
实现测试与Conda环境的自动匹配(适配你的Snakemake工作流)
Pytest本身没有原生的Conda环境自动切换功能,但可以通过自定义fixture、插件或者结合Snakemake的方式实现测试与对应环境的绑定,不用手动写bash脚本。以下是几种可行方案:
方案一:Pytest自定义Fixture + Conda Run
通过编写全局配置文件和fixture,根据测试文件名自动匹配对应环境,并在目标环境中执行测试代码:
- 在项目根目录创建
conftest.py,添加环境匹配逻辑:
import os import subprocess import json import pytest def get_env_yml(test_file_path): # 按规则匹配:testN.py 对应 envs/envN.yml test_basename = os.path.basename(test_file_path) env_suffix = test_basename.replace("test", "").split(".")[0] return f"envs/env{env_suffix}.yml" @pytest.fixture(scope="module") def target_conda_env(request): env_yml = get_env_yml(request.module.__file__) env_name = f"test-env-{os.path.splitext(os.path.basename(env_yml))[0]}" # 检查环境是否存在,不存在则创建 env_list_output = subprocess.check_output(["conda", "env", "list", "--json"]).decode() existing_envs = json.loads(env_list_output)["envs"] if not any(env.endswith(env_name) for env in existing_envs): subprocess.run( ["conda", "env", "create", "-f", env_yml, "-n", env_name], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) yield env_name # 可选:测试完成后删除环境(按需开启) # subprocess.run(["conda", "env", "remove", "-n", env_name, "-y"], check=True)
- 在测试文件中使用fixture,通过
conda run在目标环境执行被测脚本:
以test1.py为例:
import subprocess def test_script1(target_conda_env): # 在指定Conda环境中运行script1并验证结果 run_result = subprocess.run( ["conda", "run", "-n", target_conda_env, "python", "scripts/script1.py"], capture_output=True, text=True ) # 基础断言:脚本运行无错误 assert run_result.returncode == 0 # 添加你的业务逻辑断言,比如检查输出、生成的文件等
运行测试时直接执行:
pytest tests/
方案二:结合Snakemake管理测试(更贴合你的工作流)
既然你已经在用Snakemake构建数据处理流,直接在Snakefile中定义测试规则是最省心的方式,Snakemake会自动处理Conda环境的创建、激活和隔离:
在项目根目录创建Snakefile,添加测试规则:
# 总规则:依赖所有测试通过标记 rule all: input: "test1.passed", "test2.passed" # 测试script1的规则,绑定env1.yml环境 rule test_script1: input: script="scripts/script1.py", env_config="envs/env1.yml" output: touch("test1.passed") # 测试通过后生成标记文件 conda: "envs/env1.yml" # 指定使用的Conda环境配置 shell: """ python -m pytest tests/test1.py -v """ # 测试script2的规则,绑定env2.yml环境 rule test_script2: input: script="scripts/script2.py", env_config="envs/env2.yml" output: touch("test2.passed") conda: "envs/env2.yml" shell: """ python -m pytest tests/test2.py -v """
运行所有测试只需执行:
snakemake --use-conda -j 2 # -j 2表示并行运行两个测试
Snakemake会自动处理环境的创建、激活,测试完成后清理环境(可选),还能利用其依赖管理机制,只有当脚本或环境配置变化时才重新运行测试。
方案三:使用Pytest插件(简便非原生)
如果可以接受使用第三方插件,pytest-conda能快速实现测试与环境的绑定:
- 安装插件:
pip install pytest-conda
- 在测试文件中用标记指定对应环境:
以test1.py为例:
import pytest from scripts import script1 # 标记该测试使用env1.yml环境 @pytest.mark.conda_env("envs/env1.yml") def test_script1(): # 直接编写测试逻辑,插件会自动在目标环境中执行 process_result = script1.run() assert process_result == expected_output
- 运行测试:
pytest --conda-envs-dir ./envs tests/
插件会自动创建所需环境,并在对应环境中执行标记的测试用例。
内容的提问来源于stack exchange,提问作者spo
相关产品推荐
相关产品推荐

