如何将环境变量传递给pytest

Posted

技术标签:

【中文标题】如何将环境变量传递给pytest【英文标题】:How to pass environment variables to pytest 【发布时间】:2016-07-08 13:13:50 【问题描述】:

在我开始在我的 Python 项目中执行测试之前,我读取了一些环境变量并使用读取的这些值设置了一些变量。我的测试将根据读取的这些值在所需的环境中运行。

例如:假设环境变量被称为ENV_NAMEENV_NUMBER

现在,我想使用 py.test 运行测试。

如果我对这些环境变量进行硬编码,例如:ENV_NAME = 'staging', ENV_NUMBER = '5' 在我的代码中,然后通过在项目目录的根目录下执行 py.test 命令运行测试,所有测试都会成功运行。

但是,我不想硬编码这些值。有没有办法,我可以将这些环境变量作为 py.test 的命令行参数发送?

我想更多的是

py.test -ENV_NAME='staging' -ENV_NUMBER='5'.

但是,这行不通。

【问题讨论】:

这是一个可能有帮助的类似问题:***.com/questions/54900785/… 【参考方案1】:

虽然其他答案有效,但我认为这个答案更“放手”和自动化,并且更多地模拟了正常操作。所以我使用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()
    config_service.config_folder_path != None
    config_service.config_folder_name != None

我认为如果你想测试你的整个逻辑会更好:

从特定位置的.env 文件中读取变量并 根据该文件中的值检查您正在测试的代码是否按预期执行(也许您可能会发现拼写错误或其他逻辑问题)

【讨论】:

【参考方案2】:

类似于 bad_coder 提到的,你可以这样做:

# test.py
def test_hello_world(monkeypatch):
    # Setup
    monkeypatch.setenv('HELLO', 'world')

    # Test
    result = hello_world()

    # Verify
    assert(result == 'world')

【讨论】:

完全看起来是正确的答案,但对我不起作用,我不知道为什么。【参考方案3】:
    当我不在函数外部加载环境变量变量时,我使用猴子补丁。
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]

【讨论】:

另一个monkeypatch的例子,见:aalvarez.me/posts/pytest-tricks-for-better-python-tests【参考方案4】:

除了其他答案。有一个选项可以覆盖 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 变量将在您的应用程序中可用。

【讨论】:

你可以只添加一个环境变量而不是全部覆盖吗? @red888 “覆盖所有这些”是什么意思?它只是在 env 中添加了一个新变量【参考方案5】:

我终于找到了我想要的答案。

我们可以在使用 py.test 运行测试之前像这样设置环境变量

ENV_NAME='staging' ENV_NUMBER='5' py.test

【讨论】:

以后怎么用? 只需在变量前附加 $ 符号。例如,$ENV_NAME 你的意思是你只是设置环境变量(例如在 bash 中,通过export 命令)?还是你做了其他事情? 什么解决方案,设置环境变量,设置环境变量。希望有一个真正的解决方案…… 在您的问题中,您已经写到您不想硬编码值,并且您已经接受了自己的解决方案来做到这一点?【参考方案6】:

在子shell(括在括号内)内运行export,以免弄乱本地环境。使用来自.env 文件的参数提供导出。

(export $(xargs < .env); pytest -svvvx api)

【讨论】:

【参考方案7】:

有几种方法可以实现这一目标

    如果不想使用环境变量,可以使用pytest addoptions as 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"]

【讨论】:

看起来像 1. 被保存为 3. 几乎!!除了第一个是从conftest调用的fixture之外,第二个是直接从test调用的。 @Macintosh_89 您能否提供有关技术 2 的更多信息?这个包装器是否能够有条件地将环境变量分配给目录中的特定测试? @ChrisGuest,您是指特定的测试文件还是文件中的测试?无论您在pytest.main('-s' ,pytest_args,test_file.py) 中传递什么args,都应该在test_file.py 中可用。如果不清楚,您能否详细说明您的要求?【参考方案8】:

遵循@tutuDajuju 提供的想法,使用pytest-env - 另一种方法是使用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 =========

【讨论】:

【参考方案9】:

另一种选择是使用pytest-env 插件。可以这样配置:

[pytest]
env = 
    HOME=~/tmp
    D:RUN_ENV=test

D: 前缀允许设置默认值,并且不会覆盖传递给 py.test 的现有变量。

注意:您可以使用自定义配置显式运行 pytest,如果您只是有时需要运行专门的环境设置:

pytest -c custom_pytest.ini

如果您使用 PyCharm 与 pytest-dotenv,this 可能会有所帮助

【讨论】:

使用pytest-dotenv 成功获取了我的.env 文件中定义的环境变量,并在运行pytest 时使它们可用。【参考方案10】:

我需要创建一个pytest.ini 文件将环境变量传递给pytest 命令。例如:

在 pytest.ini 文件中,我设置了一个空值,因为它会被您传递给命令行命令的任何内容覆盖:

[pytest]
MY_ENV_VAR=

命令行,设置实际值:

$ MY_ENV_VAR=something pytest -c pytest.ini -s tests/**

我不知道为什么会这样。我刚刚发现它只是反复试验的结果,因为其他答案对我没有帮助。

【讨论】:

@Acumenus 正如你所说,它似乎。但实际情况并非如此,因为删除 pytest.ini 中的条目将导致 CLI env var 被忽略。 在 CLI 上定义的环境变量将可用于整个 Python 进程,并且与 pytest 无关。为了争论,考虑$ FOO=bar python -c 'import os; print(os.environ["FOO"])'。如果 CLI env var 被忽略,那么您的应用程序不得将其作为 env var 访问,而是以其他方式访问。 @Acumenus 我的答案是 pytest 特定的。你所说的在理论上都是正确的,但正如我在回答中解释的那样,我不知道为什么 pytest 需要关于环境变量的解决方法,但它确实需要这种解决方法。跨度> 我遇到了和你一样的问题。我在我的测试目录中创建了一个简单的 shell 脚本run-test.sh。它包含以下一行:ENV_VAR_NAME_1="env_var_value_1" ENV_VAR_NAME_2="env_var_value_2" pytest -c path/to/pytest.ini path/to/test/ 必须将其放在一行;否则,pytest 不会加载环境变量。使用chmod +x run-test.sh 启用shell 脚本执行。您现在可以通过运行 ./run-test.sh 来运行 pytest 测试。

以上是关于如何将环境变量传递给pytest的主要内容,如果未能解决你的问题,请参考以下文章

如何将环境变量传递给前端 Web 应用程序?

如何将环境变量传递给传递给xmllint的命令?

将主机环境变量传递给 dockerfile

我应该如何将敏感的环境变量传递给 Amazon ECS 任务?

如何使用 process.env 将环境变量中的 API 密钥传递给 Ember CLI?

如何在传递 ShellCheck 时通过环境变量将 glob 传递给 shell 脚本