如何在加载pytest脚本前使用python-dotenv读取.env环境变量
问题根因
你当前的问题本质是pytest fixture的执行时机晚于测试模块的导入阶段:你定义的load_env自动fixture会在pytest完成所有测试文件导入、正式开始执行测试用例前才运行,但测试文件里的if RUN_TESTS_LOCALLY:判断是模块被导入时就执行的,所以.env里的变量加载时判断逻辑已经走完,自然无法生效。
方案1:直接在conftest.py顶层加载.env(最快捷,无需修改现有测试代码)
conftest.py是pytest启动后最先加载的文件之一,早于所有测试模块的导入,你只需要把load_dotenv()的调用从fixture里移到conftest.py的最顶部即可:
# conftest.py 最顶部直接加载.env import os from dotenv import load_dotenv # 加载.env文件,默认不会覆盖已经手动export的系统环境变量 load_dotenv() # 其余原有conftest逻辑、fixture定义保留即可 import pytest @pytest.fixture(scope='session', autouse=True) def load_env(): print("环境变量已提前加载完成") # 这里不需要再调用load_dotenv了
这个方案不需要修改你现有的测试文件逻辑,.env里定义的RUN_TESTS_LOCALLY就能被测试文件的模块级判断正常识别。
方案2:用pytest-dotenv插件自动加载(零代码修改)
直接安装pytest-dotenv插件,它会在pytest启动的最早期自动加载项目根目录的.env文件,不需要你自己写任何加载逻辑:
- 安装命令:
pip install pytest-dotenv - 安装后直接运行
pytest -vs .即可,原有所有代码逻辑不需要调整,.env里的变量会被正常识别。
方案3:优化测试写法,避免模块级条件判断(更易维护)
你可以把运行环境的判断逻辑放到fixture里,测试函数只需要写一次,不需要分两个分支定义,完全不需要纠结环境变量的加载时机:
# simple_test_runner.py 修改后代码 import os import pytest THIS_FOLDER = os.path.dirname(os.path.realpath(__file__)) @pytest.fixture(scope="function") def test_executor(run_process, function_scoped_container_getter): run_local = os.environ.get('RUN_TESTS_LOCALLY') if run_local: # 返回本地执行函数 def _run_test(): return run_process(f"python3 {THIS_FOLDER}/simple_test.py") return _run_test else: # 返回容器内执行函数,统一输出格式和本地执行对齐 def _run_test(): container = function_scoped_container_getter.get("container_name") exec_result = container.create_exec("python3 /simple_test.py") return exec_result.output, exec_result.returncode return _run_test def test_simple(test_executor): output, returncode = test_executor() assert returncode == 0
这种写法后续新增测试用例不需要重复写分支判断逻辑,直接复用test_executor fixture即可,同时兼容手动export环境变量、.env文件加载两种场景。
内容的提问来源于stack exchange,提问作者Evandro Coan
相关产品推荐
相关产品推荐

