Pydantic设置管理+FastAPI:如何在pytest测试期间忽略.env文件?

6

我在基于FastAPI的项目中使用Pydantic设置管理。我有一个像下面这样的Settings类:

class Settings(BaseSettings):
    FOO: str = ''
    BAR: int = 0

    class Config:
        env_file = "path/to/.my_env_file")
        env_nested_delimiter = "__"

path/to/.my_env_file 文件包含了 FOOBAR 值。

在测试期间,我需要有选择性地对 Settings 进行补丁操作,并且不想从 path/to/.my_env_file 中读取任何内容。例如:

path/to/.my_env_file

FOO=i_do_not_wanna_read_this
BAR=100

我的测试文件:

@lru_cache()
def get_settings():
    return Settings()

def get_settings_override() -> Settings:
    return Settings(
        FOO = 'foo'
    )

app.dependency_overrides[get_settings] = get_settings_override

我想要运行测试,其中一个测试参数为FOO='foo',另一个测试参数为默认值的BAR=0(忽略path/to/.my_env_file文件内的内容)。在上述代码中,我成功得到了FOO='foo',但是BAR仍从path/to/.my_env_file中读取(即,BAR=100)。是否有一种简单明了的方法来处理这个问题?
2个回答

1

虽然我在文档或其他页面中找不到直接的解决方案,但这对我的测试有效:

使用tox时,请按照此Stack Overflow问题,将以下内容放入您的tox.ini中:

[testenv]
setenv = TOX_TESTENV = true

您可以使用以下代码片段来覆盖您的env_file设置:
import os

# ... snip ...

if os.environ.get("TOX_TESTENV") is not None:
    Settings.Config.env_file = ""

类似的方法,例如通过检查sys.argv中是否存在"test"或检查是否加载了unittest也可以正常工作:

import sys

# ... snip ...

if len(sys.argv) > 1 and "pytest" in sys.argv[0]:
    Settings.Config.env_file = ""

太棒了,一个自定义钩子 def pytest_configure(): Settings.Config.env_file = '' 解决了我的测试套件问题。非常感谢你的分享! - hoefling

0
你可以在pytest fixture中使用monkeypatch:
import pytest

from app.settings import Settings


@pytest.fixture(autouse=True, scope="function")
def patch_settings_env_file_location(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(Settings.Config, "env_file", "")


在这个特定的情况下,我已经在我的测试根目录下的conftest.py中定义了patch_settings_env_file_location

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接