为什么FastAPI搭配PyTest做路由测试时报Settings不可调用错误
错误原因
1. 核心错误:依赖重写时错误执行了覆盖函数
你在conftest.py中配置依赖覆盖的代码存在语法错误:
# 错误写法:调用了get_settings_override(),将返回的Settings实例赋值给了依赖映射 app.dependency_overrides[get_settings] = get_settings_override()
FastAPI的dependency_overrides要求映射的右值是可调用的依赖函数本身,而非函数执行后的返回值。你当前将get_settings的覆盖值设为了一个Settings实例,当FastAPI尝试调用该依赖时,就会抛出「Settings对象不是可调用对象」的报错,和你收到的错误信息完全吻合。
2. 认知偏差:AnyUrl类型的结构是正常的
你观察到的database_url包含password、port、path等参数属于正常现象:你将该字段声明为AnyUrl类型,Pydantic会自动把字符串格式的数据库连接串解析为AnyUrl对象,该对象本身就内置了拆分后的连接串属性,并非和你定义的Settings类结构不符,如果需要原始字符串格式的连接串,调用str(settings.database_url)即可获取。
另外testing字段的默认值写法存在小隐患:os.getenv("TESTING", 0)返回值要么是字符串要么是整数0,虽然Pydantic会自动转布尔类型,但建议直接使用BaseSettings的原生环境变量读取能力,不需要手动调用os.getenv,可以避免很多类型转换问题。
修复方法
第一步:修正conftest.py的依赖覆盖写法
去掉get_settings_override后的调用括号,直接赋值函数本身即可:
@pytest.fixture(scope="module") def test_app(): app = create_application() # 正确写法:传入函数对象,不要执行调用 app.dependency_overrides[get_settings] = get_settings_override with TestClient(app) as test_client: yield test_client
第二步(可选):优化Settings类写法
删除手动的os.getenv调用,交由BaseSettings自动处理环境变量读取,写法更简洁也更不容易出错:
class Settings(BaseSettings): environment: str = "dev" testing: bool = False database_url: AnyUrl class Config: case_sensitive = False # 可选配置,环境变量不区分大小写
验证
修改完成后重新运行测试,TypeError会直接消失,测试也能正确读取到覆盖后的测试配置,容器也会正常进入测试模式。
内容的提问来源于stack exchange,提问作者Alex Goncalves

