You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Pytest模拟FastAPI的app.state对象以测试健康检查接口

如何使用Pytest模拟FastAPI的app.state对象以测试健康检查接口

嗨,我来帮你解决这个问题!你的测试报错AttributeError: 'State' object has no attribute 'db_client',本质是因为测试用的FastAPI实例里没有初始化app.state.db_client,而你的健康检查接口正好依赖这个对象的is_connected属性。下面给你几种实用的解决方案:

方案一:手动创建模拟对象注入到app.state

这种方式简单直接,适合快速验证测试场景。我们可以在test_app fixture里,先获取app实例,然后手动添加一个模拟的db_client到app.state中:

@pytest.fixture(scope="module")
def test_app():
    # 获取你的FastAPI应用实例
    app = get_app()
    
    # 定义一个模拟的DB客户端类,实现接口需要的is_connected属性
    class MockDBClient:
        is_connected = True  # 默认模拟已连接状态
    
    # 将模拟对象注入到app.state
    app.state.db_client = MockDBClient()
    
    # 创建TestClient并返回
    client = TestClient(app)
    yield client

修改后再运行test_liveness,就能正常通过了,因为接口能找到app.state.db_client,且is_connected为True。

方案二:使用unittest.mock创建灵活的模拟对象

如果需要测试多种场景(比如健康/不健康状态),可以用Python标准库的unittest.mock来创建更灵活的Mock对象,方便动态修改属性值:

from unittest.mock import Mock

@pytest.fixture(scope="function")
def test_app_with_mock_db():
    app = get_app()
    # 创建一个Mock对象,模拟db_client的行为
    mock_db_client = Mock()
    mock_db_client.is_connected = True  # 默认已连接
    app.state.db_client = mock_db_client
    
    client = TestClient(app)
    # 同时返回client和mock对象,方便测试中修改属性
    yield client, mock_db_client

# 测试健康状态场景
def test_liveness_ready(test_app_with_mock_db):
    client, mock_db = test_app_with_mock_db
    response = client.get("/health/liveness")
    assert response.status_code == 200
    assert response.json() == {"status": "ready"}

# 测试不健康状态场景
def test_liveness_not_ready(test_app_with_mock_db):
    client, mock_db = test_app_with_mock_db
    # 动态修改mock对象的is_connected属性为False
    mock_db.is_connected = False
    response = client.get("/health/liveness")
    assert response.status_code == 503

这种方式能覆盖更多测试场景,验证接口在不同状态下的表现。

方案三:通过依赖注入传入模拟对象(更优雅的方式)

如果你的get_app或create_app函数支持扩展,可以修改它,允许传入db_client作为参数,这样测试时直接传入模拟对象,更符合依赖注入的设计思想:

首先修改get_app函数:

def get_app(db_client=None):
    settings = get_settings()
    config = {...}
    application = create_app(**config)
    
    # 如果传入了db_client,就赋值给app.state
    if db_client:
        application.state.db_client = db_client
    return application

然后在测试fixture中使用:

from unittest.mock import Mock

@pytest.fixture(scope="module")
def test_app():
    # 创建模拟的db_client
    mock_db_client = Mock(is_connected=True)
    # 传入模拟对象创建app
    app = get_app(db_client=mock_db_client)
    client = TestClient(app)
    yield client

这种方式让测试代码和业务代码解耦,后续维护起来更方便。

备注:内容来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 15:18:06