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

测试FastAPI startup事件导致其他测试失败,如何解决?

问题解决:FastAPI Startup事件测试导致其他测试用例失败

问题场景

  • 环境:Python 3.9.7、FastAPI 0.82.0
  • Startup事件代码:
@app.on_event("startup")
def startup_event():
    utils.remote_example_call()
  • 测试用例代码:
def test_startup_event():
    with patch("app.utils.remote_example_call") as mock_remote_example_call:
        mock_remote_example_call.return_value = None
        with TestClient(app) as client:
            response = client.get("/health")
        assert response.status_code == 200
        assert mock_remote_example_call.call_count == 1
  • 执行测试命令:
pytest /tests/unit/ --asyncio-mode=strict
  • 错误现象:test_get_database测试失败,错误信息:
AssertionError: assert <botocore.client.DynamoDB object at 0xffffad29f910> == 'my_database'

注释掉test_startup_event测试用例后,所有测试可正常运行。

原因分析

FastAPI的app是全局单例对象,当TestClient启动时会触发startup事件,事件执行过程中可能初始化了全局共享资源(比如数据库客户端实例),这些资源会污染后续测试用例的mock环境,导致test_get_database的断言不符合预期。

解决办法

方法1:用测试夹具隔离FastAPI应用实例

为每个测试用例创建独立的应用实例,避免全局状态共享:

import pytest
from fastapi import FastAPI
from starlette.testclient import TestClient
from unittest.mock import patch

@pytest.fixture
def isolated_app():
    # 重新构建应用实例,而非使用全局app
    app = FastAPI()

    # 复制main.py中的路由与事件配置
    @app.on_event("startup")
    def startup_event():
        import app.utils
        app.utils.remote_example_call()

    @app.get("/health")
    def health_check():
        return {"status": "healthy"}

    return app

def test_startup_event(isolated_app):
    with patch("app.utils.remote_example_call") as mock_call:
        mock_call.return_value = None
        with TestClient(isolated_app) as client:
            response = client.get("/health")
        assert response.status_code == 200
        assert mock_call.call_count == 1

方法2:测试后重置全局资源状态

如果必须使用全局app,在测试完成后手动清理startup事件初始化的全局资源:

def test_startup_event():
    with patch("app.utils.remote_example_call") as mock_call:
        mock_call.return_value = None
        with TestClient(app) as client:
            response = client.get("/health")
        assert response.status_code == 200
        assert mock_call.call_count == 1

    # 重置全局数据库实例(根据实际代码调整变量名)
    import app.repository_helper
    app.repository_helper._database_instance = None

方法3:自动夹具清理全局状态

创建自动运行的pytest夹具,在每个测试前后恢复全局状态:

import pytest

@pytest.fixture(autouse=True)
def reset_global_resources():
    # 测试前保存原始状态
    import app.repository_helper
    original_db = app.repository_helper._database_instance

    yield

    # 测试后恢复原始状态
    app.repository_helper._database_instance = original_db

内容的提问来源于stack exchange,提问作者writes_on

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:25:15