繁体   English   中英

如何在 conftest.py 中使用 pytest 修补环境?

[英]How to monkeypatch the environment using pytest in conftest.py?

我的主文件中有一个全局对象

# reporter.py

from os import environ
from influxdb import InfluxDBClient

influxdb_client = InfluxDBClient(host=environ['INFLUXCLOUD_HOST'],
                                 username=environ['INFLUXCLOUD_USERNAME'],
                                 password=environ['INFLUXCLOUD_PASSWORD'],
                                 ssl=True,
                                 timeout=4*60)

def foo():
    pass

我正在使用 pytest,我想为这些环境变量设置假值。 我的 conftest.py 中有以下内容:

# conftest.py

import pytest

@pytest.fixture(scope='session', autouse=True)
def setup_env(monkeypatch):
    monkeypatch.setenv('INFLUXCLOUD_HOST', 'host')
    monkeypatch.setenv('INFLUXCLOUD_USERNAME', 'username')
    monkeypatch.setenv('INFLUXCLOUD_PASSWORD', 'password')

然而,当我import reporter在我的测试文件,我得到一个KeyError是INFLUXCLOUD_HOST在ENV失踪。

为什么pytest不执行setup_env和monkeypatch我的环境? 有没有办法这样做?

这里的问题在于误解会话范围的夹具是什么。

要知道哪些测试和自动固定装置确实存在,pytest需要导入测试文件和conftest插件。 然后它会扫描导入的模块,并查找夹具和测试函数以及测试类等。这在pytest术语中称为“集合”。

只有在收集完所有测试之后,pytest才会决定执行它们,并安排执行计划,特别是在准备好灯具时。 会话范围的装置首先准备好并在最后进行拆解 - 在任何测试开始之前,并且在所有测试完成之后。

但是,导入测试文件和conftest会假定执行这些模块 - 导入任何其他与pytest无关的Python模块。

因此,当您从测试文件中import reporter时,或者即使将该全局变量直接放入测试文件中,也会执行此模块,并尝试使用env变量。 但是灯具还没有被执行(并且pytest还不知道它们的存在)。 因此,它失败了。

即使您将从测试函数内部import reporter ,这也无济于事,因为pytest可能会在收集阶段之前尝试导入该reporter.py模块。 由于缺少测试函数/类,Pytest会将其过滤掉,但导入尝试将完成并将失败。

这里最好的解决方案是将客户端“打包”到一个夹具中并使用该夹具而不是全局变量。

pytest 6.2 开始,您可以直接使用MonkeyPatch对象而不是monkeypatch固定装置,作为实例或上下文管理器。

(谢尔盖已经提供了关于“为什么”问题的坚实背景;这试图解决“如何”。)

上下文管理器(推荐):

因为与monkeypatch固定装置不同,直接创建的实例不会自动undo() -ed。

# test_reporter.py

from pytest import MonkeyPatch


def test_get_client_username():
    with MonkeyPatch.context() as mp:
        mp.setenv('INFLUXCLOUD_HOST', 'host')
        mp.setenv('INFLUXCLOUD_USERNAME', 'username')
        mp.setenv('INFLUXCLOUD_PASSWORD', 'password')

        from src.reporter import influxdb_client

        assert influxdb_client._username == 'username'

直接使用实例:

# conftest.py

from pytest import MonkeyPatch


mp = pytest.MonkeyPatch()
mp.setenv('INFLUXCLOUD_HOST', 'host')
mp.setenv('INFLUXCLOUD_USERNAME', 'username')
mp.setenv('INFLUXCLOUD_PASSWORD', 'password')

假设文件结构供参考:

src/
    reporter.py
    __init__.py
test/
    conftest.py
    test_reporter.py

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM