如何使用pytest测试FastAPI应用,避免测试间共享应用状态
解决FastAPI+pytest测试中全局状态污染的问题
你的问题核心是测试会话中共享了同一个全局状态,导致测试用例互相干扰。以下是几种可行的解决方案:
方法1:测试前自动重置全局状态
利用pytest的autouse fixture,在每个测试执行前重置目标模块的全局变量。
创建conftest.py文件(pytest会自动加载该文件):
import pytest import main @pytest.fixture(autouse=True) def reset_global_state(): # 测试前重置初始状态 main.my_state = False yield # 测试结束后再次重置(可选,确保后续测试不受影响) main.my_state = False
修改后,所有测试用例执行前都会自动把my_state恢复为初始的False,测试间不会互相干扰。
方法2:用工厂函数创建独立App实例
将App的创建逻辑封装成工厂函数,每次测试生成全新的App实例,彻底隔离状态。
修改main.py:
from fastapi import FastAPI def create_app(): app = FastAPI() # 将状态存储在app的state属性中,而非全局变量 app.state.my_state = False @app.get("/my_state/") def return_my_state(): return {"state": app.state.my_state } @app.post("/my_state/") def set_my_state(content: dict): app.state.my_state = content['set'] return app # 保留全局app实例,方便正常启动服务 app = create_app()
在conftest.py中定义测试用的client fixture:
import pytest from fastapi.testclient import TestClient from main import create_app @pytest.fixture def client(): # 每个测试都生成全新的App和Client app = create_app() return TestClient(app)
修改测试文件(以test_file1.py为例):
import pytest @pytest.mark.asyncio async def test_check_status(client): client.post("/my_state/", json={"set": True}) assert client.get("/my_state/").json()['state'] is True
test_file2.py同理,每个测试用例都会拿到独立的App实例,状态完全隔离。
方法3:用依赖注入管理状态
将状态封装为依赖类,测试时通过覆盖依赖来重置状态,更符合FastAPI的设计规范。
修改main.py:
from fastapi import FastAPI, Depends class AppState: def __init__(self): self.my_state = False def get_app_state(): return AppState() app = FastAPI() @app.get("/my_state/") def return_my_state(state: AppState = Depends(get_app_state)): return {"state": state.my_state } @app.post("/my_state/") def set_my_state(content: dict, state: AppState = Depends(get_app_state)): state.my_state = content['set']
在conftest.py中定义带依赖覆盖的client fixture:
import pytest from fastapi.testclient import TestClient from main import app, AppState, get_app_state @pytest.fixture def client(): # 每次测试创建全新的状态实例 def override_get_state(): return AppState() app.dependency_overrides[get_app_state] = override_get_state client = TestClient(app) yield client # 测试结束后清除依赖覆盖,避免影响其他测试 app.dependency_overrides.clear()
测试文件的写法与方法2一致,每个测试都会使用独立的状态实例。
内容的提问来源于stack exchange,提问作者ntriisii
相关产品推荐
相关产品推荐

