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

flo*_*urr 6 python pytest pydantic fastapi

我在基于 FastAPI 的项目中使用Pydantic 设置管理。我有Settings一堂这样的课:

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

    class Config:
        env_file = "path/to/.my_env_file")
        env_nested_delimiter = "__"
Run Code Online (Sandbox Code Playgroud)

该文件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
Run Code Online (Sandbox Code Playgroud)

我的测试文件:

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

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

app.dependency_overrides[get_settings] = get_settings_override
Run Code Online (Sandbox Code Playgroud)

我想使用FOO='foo'BAR 的默认值 和 运行测试(即,BAR=0忽略 的内容path/to/.my_env_file。在上面的代码中,我得到FOO='foo'但仍然从(即,)BAR读取path/to/.my_env_fileBAR=100

有没有直接的方法来处理这个问题?

小智 1

虽然我在文档或任何其他页面中找不到简单的解决方案,但这适用于我的测试:

使用 tox 时,请将其放入您的 中tox.ini,按照Stack Overflow 问题

[testenv]
setenv = TOX_TESTENV = true
Run Code Online (Sandbox Code Playgroud)

然后,您可以简单地使用以下代码片段来覆盖您的env_file设置:

import os

# ... snip ...

if os.environ.get("TOX_TESTENV") is not None:
    Settings.Config.env_file = ""           # Pydantic 1.x
    Settings.model_config["env_file"] = ""  # Pydantic 2.x
Run Code Online (Sandbox Code Playgroud)

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

import sys

# ... snip ...

if len(sys.argv) > 1 and "pytest" in sys.argv[0]:
    Settings.Config.env_file = ""           # Pydantic 1.x
    Settings.model_config["env_file"] = ""  # Pydantic 2.x
Run Code Online (Sandbox Code Playgroud)

或者,这是@hoefling的解决方案,利用pytest hooks

def pytest_configure():
    Settings.Config.env_file = ""           # Pydantic 1.x
    Settings.model_config["env_file"] = ""  # Pydantic 2.x
Run Code Online (Sandbox Code Playgroud)