如何将环境变量传递给pytest
How to pass environment variables to pytest
在我的 Python 项目中开始执行测试之前,我读取了一些环境变量并使用读取的这些值设置了一些变量。我的测试将根据读取的这些值在所需的环境中 运行。
例如:假设环境变量被称为 ENV_NAME
和 ENV_NUMBER
现在,我想 运行 使用 py.test 进行测试。
如果我硬编码这些环境变量,例如:在我的代码中 ENV_NAME = 'staging', ENV_NUMBER = '5'
然后通过在项目目录的根目录执行 py.test 命令来 运行 测试,所有测试 运行 成功。
但是,我不想对这些值进行硬编码。有没有办法,我可以将这些环境变量作为 py.test?
的命令行参数发送
我想的更多是
py.test -ENV_NAME='staging' -ENV_NUMBER='5'.
但是,这不起作用。
实现此目的的方法很少
如果你不想使用环境变量,你可以使用pytest addoptions作为https://docs.pytest.org/en/latest/example/simple.html
你可以像这样写一个封装脚本来调用环境变量
import os
import py
env_name = os.environ["ENV_NAME"]
env_no = os.environ["ENV_NUMBER"]
pytest_args=(env_name,env_no)
pytest.main('-s' ,pytest_args,test_file.py)
在test_file.py
你可以使用
env_n, env_n = pytest.config.getoption('pytest_args')
- 如果你只是想传递日期而不是设置环境变量的替代方法
在命令行上,您可以将其用作
py.test --testdata ="ENV_NAME:staging,ENV_NUMBER:5"
您可以在您的测试文件中使用
pytest_params = pytest.config.getoption('testdata')
params = pytest_params.split(":")
param_dict = dict(params[i:i+2] for i in range(0,len(params),2))
env_name = param_dict["ENV_Name"]
我终于找到了我一直在寻找的答案。
我们可以在使用 py.test
运行 测试之前像这样设置环境变量
ENV_NAME='staging' ENV_NUMBER='5' py.test
另一种选择是使用 pytest-env 插件。可以这样配置:
[pytest]
env =
HOME=~/tmp
D:RUN_ENV=test
D:
前缀允许设置默认值,并且不会覆盖传递给 py.test
的现有变量。
注意:如果您只是有时需要运行 专门的环境设置,您可以使用自定义配置显式运行 pytest:
pytest -c custom_pytest.ini
如果你使用 PyCharm vs pytest-dotenv,this 可能会有帮助
- 当我不在函数外加载环境变量变量时,我使用猴子补丁。
import os
# success.py
def hello_world():
return os.environ["HELLO"]
# fail.py
global_ref = os.environ["HELLO"] # KeyError occurs this line because getting environment variable before monkeypatching
def hello_world():
return global_ref
# test.py
def test_hello_world(monkeypatch):
# Setup
envs = {
'HELLO': 'world'
}
monkeypatch.setattr(os, 'environ', envs)
# Test
result = hello_world()
# Verify
assert(result == 'world')
- 如果使用PyCharm可以设置环境变量,
[Run]
-> [Edit Configuration]
-> [Defaults]
-> [py.tests]
-> [Environment Variables]
除其他答案外。有一个选项可以覆盖 conftest.py
中的 pytest_generate_tests
并在那里设置 ENV 变量。
例如,将以下内容添加到 conftest.py
中:
import os
def pytest_generate_tests(metafunc):
os.environ['TEST_NAME'] = 'My super test name| Python version {}'.format(python_version)
此代码将允许您在测试应用程序中获取 TEST_NAME
ENV 变量。你也可以做一个夹具:
import os
import pytest
@pytest.fixture
def the_name():
return os.environ.get('TEST_NAME')
此外,此 ENV 变量将在您的应用程序中可用。
我需要创建一个 pytest.ini
文件 并且 将环境变量传递给 pytest
命令。例如:
在 pytest.ini 文件中,我设置了一个空值,因为它会被传递给命令行命令的任何内容覆盖:
[pytest]
MY_ENV_VAR=
命令行,设置实际值:
$ MY_ENV_VAR=something pytest -c pytest.ini -s tests/**
我不知道为什么会这样。我刚刚发现它只是反复试验的结果,因为其他答案对我没有帮助。
遵循@tutuDajuju 使用 pytest-env - an alternative would be to write a custom plugin leveraging pytest_load_initial_conftests 提供的想法。可能很有用,尤其是当您不想或不能安装外部依赖项时。
这是一个简单的例子:
项目结构
.
├── __init__.py
├── pytest.ini
├── script.py
└── tests
├── __init__.py
├── plugins
│ ├── __init__.py
│ └── env_vars.py
└── test_script.py
script.py
import os
FOOBAR = os.environ.get("FOOBAR")
def foobar():
return FOOBAR
test_script.py
from script import foobar
def test_foobar():
assert foobar() == "foobar"
pytest.ini
[pytest]
addopts = -p tests.plugins.env_vars
env_vars.py
import os
import pytest
@pytest.hookimpl(tryfirst=True)
def pytest_load_initial_conftests(args, early_config, parser):
os.environ["FOOBAR"] = "foobar"
示例运行:
$ python -m pytest tests -v
========= test session starts =========
platform darwin -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 --
rootdir: /Users/user/pytest_plugins, inifile: pytest.ini
collected 1 item
tests/test_script.py::test_foobar PASSED [100%]
========= 1 passed in 0.01s =========
运行 export
在子外壳(括起来的括号)内,不要弄乱本地环境。使用 .env
文件中的参数提供导出。
(export $(xargs < .env); pytest -svvvx api)
类似于bad_coder提到的,你可以这样做:
# test.py
def test_hello_world(monkeypatch):
# Setup
monkeypatch.setenv('HELLO', 'world')
# Test
result = hello_world()
# Verify
assert(result == 'world')
虽然另一个答案有效,但我认为这个答案更“放手”和自动化,它更多地模拟正常操作。所以我使用 python-dotenv
加载所有变量形成一个文件 load_dotenv(my_filepath)
:
import os
import pytest
from dotenv import load_dotenv
from core import ConfigService
def test_config_service():
"""This test ensures that the config service can read the environment
variables which define the location of the config.json files"""
load_dotenv("env/common.env")
config_service = ConfigService()
config_service.load()
assert config_service.config_folder_path is not None
assert config_service.config_folder_name is not None
我认为如果你想测试你的整个逻辑会更好:
- 从特定位置的
.env
文件中读取变量并且
- 根据该文件中的值检查您正在测试的代码是否按预期执行(也许您会发现拼写错误或其他逻辑问题)
当您的环境变量是动态的时,您可以使用 monkeypatching,它与 pytest
捆绑在一起。
在我的 Python 项目中开始执行测试之前,我读取了一些环境变量并使用读取的这些值设置了一些变量。我的测试将根据读取的这些值在所需的环境中 运行。
例如:假设环境变量被称为 ENV_NAME
和 ENV_NUMBER
现在,我想 运行 使用 py.test 进行测试。
如果我硬编码这些环境变量,例如:在我的代码中 ENV_NAME = 'staging', ENV_NUMBER = '5'
然后通过在项目目录的根目录执行 py.test 命令来 运行 测试,所有测试 运行 成功。
但是,我不想对这些值进行硬编码。有没有办法,我可以将这些环境变量作为 py.test?
的命令行参数发送我想的更多是
py.test -ENV_NAME='staging' -ENV_NUMBER='5'.
但是,这不起作用。
实现此目的的方法很少
如果你不想使用环境变量,你可以使用pytest addoptions作为https://docs.pytest.org/en/latest/example/simple.html
你可以像这样写一个封装脚本来调用环境变量
import os import py env_name = os.environ["ENV_NAME"] env_no = os.environ["ENV_NUMBER"] pytest_args=(env_name,env_no) pytest.main('-s' ,pytest_args,test_file.py)
在test_file.py 你可以使用
env_n, env_n = pytest.config.getoption('pytest_args')
- 如果你只是想传递日期而不是设置环境变量的替代方法
在命令行上,您可以将其用作
py.test --testdata ="ENV_NAME:staging,ENV_NUMBER:5"
您可以在您的测试文件中使用
pytest_params = pytest.config.getoption('testdata')
params = pytest_params.split(":")
param_dict = dict(params[i:i+2] for i in range(0,len(params),2))
env_name = param_dict["ENV_Name"]
我终于找到了我一直在寻找的答案。
我们可以在使用 py.test
运行 测试之前像这样设置环境变量ENV_NAME='staging' ENV_NUMBER='5' py.test
另一种选择是使用 pytest-env 插件。可以这样配置:
[pytest]
env =
HOME=~/tmp
D:RUN_ENV=test
D:
前缀允许设置默认值,并且不会覆盖传递给 py.test
的现有变量。
注意:如果您只是有时需要运行 专门的环境设置,您可以使用自定义配置显式运行 pytest:
pytest -c custom_pytest.ini
如果你使用 PyCharm vs pytest-dotenv,this 可能会有帮助
- 当我不在函数外加载环境变量变量时,我使用猴子补丁。
import os
# success.py
def hello_world():
return os.environ["HELLO"]
# fail.py
global_ref = os.environ["HELLO"] # KeyError occurs this line because getting environment variable before monkeypatching
def hello_world():
return global_ref
# test.py
def test_hello_world(monkeypatch):
# Setup
envs = {
'HELLO': 'world'
}
monkeypatch.setattr(os, 'environ', envs)
# Test
result = hello_world()
# Verify
assert(result == 'world')
- 如果使用PyCharm可以设置环境变量,
[Run]
->[Edit Configuration]
->[Defaults]
->[py.tests]
->[Environment Variables]
除其他答案外。有一个选项可以覆盖 conftest.py
中的 pytest_generate_tests
并在那里设置 ENV 变量。
例如,将以下内容添加到 conftest.py
中:
import os
def pytest_generate_tests(metafunc):
os.environ['TEST_NAME'] = 'My super test name| Python version {}'.format(python_version)
此代码将允许您在测试应用程序中获取 TEST_NAME
ENV 变量。你也可以做一个夹具:
import os
import pytest
@pytest.fixture
def the_name():
return os.environ.get('TEST_NAME')
此外,此 ENV 变量将在您的应用程序中可用。
我需要创建一个 pytest.ini
文件 并且 将环境变量传递给 pytest
命令。例如:
在 pytest.ini 文件中,我设置了一个空值,因为它会被传递给命令行命令的任何内容覆盖:
[pytest]
MY_ENV_VAR=
命令行,设置实际值:
$ MY_ENV_VAR=something pytest -c pytest.ini -s tests/**
我不知道为什么会这样。我刚刚发现它只是反复试验的结果,因为其他答案对我没有帮助。
遵循@tutuDajuju 使用 pytest-env - an alternative would be to write a custom plugin leveraging pytest_load_initial_conftests 提供的想法。可能很有用,尤其是当您不想或不能安装外部依赖项时。
这是一个简单的例子:
项目结构
.
├── __init__.py
├── pytest.ini
├── script.py
└── tests
├── __init__.py
├── plugins
│ ├── __init__.py
│ └── env_vars.py
└── test_script.py
script.py
import os
FOOBAR = os.environ.get("FOOBAR")
def foobar():
return FOOBAR
test_script.py
from script import foobar
def test_foobar():
assert foobar() == "foobar"
pytest.ini
[pytest]
addopts = -p tests.plugins.env_vars
env_vars.py
import os
import pytest
@pytest.hookimpl(tryfirst=True)
def pytest_load_initial_conftests(args, early_config, parser):
os.environ["FOOBAR"] = "foobar"
示例运行:
$ python -m pytest tests -v
========= test session starts =========
platform darwin -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 --
rootdir: /Users/user/pytest_plugins, inifile: pytest.ini
collected 1 item
tests/test_script.py::test_foobar PASSED [100%]
========= 1 passed in 0.01s =========
运行 export
在子外壳(括起来的括号)内,不要弄乱本地环境。使用 .env
文件中的参数提供导出。
(export $(xargs < .env); pytest -svvvx api)
类似于bad_coder提到的,你可以这样做:
# test.py
def test_hello_world(monkeypatch):
# Setup
monkeypatch.setenv('HELLO', 'world')
# Test
result = hello_world()
# Verify
assert(result == 'world')
虽然另一个答案有效,但我认为这个答案更“放手”和自动化,它更多地模拟正常操作。所以我使用 python-dotenv
加载所有变量形成一个文件 load_dotenv(my_filepath)
:
import os
import pytest
from dotenv import load_dotenv
from core import ConfigService
def test_config_service():
"""This test ensures that the config service can read the environment
variables which define the location of the config.json files"""
load_dotenv("env/common.env")
config_service = ConfigService()
config_service.load()
assert config_service.config_folder_path is not None
assert config_service.config_folder_name is not None
我认为如果你想测试你的整个逻辑会更好:
- 从特定位置的
.env
文件中读取变量并且 - 根据该文件中的值检查您正在测试的代码是否按预期执行(也许您会发现拼写错误或其他逻辑问题)
当您的环境变量是动态的时,您可以使用 monkeypatching,它与 pytest
捆绑在一起。