当前位置: 首页 > news >正文

fastapi:测试: 测试带数据库连接的异步函数

一,说明:

1,测试异步函数时,你必须在函数前加上 await
     并且测试用例本身也要是 async def,同时需要打上 @pytest.mark.asyncio 标签

2,在 FastAPI 中,很多 service 层或 CRUD 函数都需要传入一个数据库 AsyncSession。
     测试这类函数时,我们可以结合 db_session 固件(Fixture)来实现。

二,代码:

数据库异步函数:

# 根据用户名查询得到用户信息的一条记录
async def get_user_by_username(db: AsyncSession, username: str):"""从数据库中异步获取用户信息"""result = await db.execute(select(User).filter(User.username == username))return result.scalars().first()

测试配置

# tests/conftest.py (API 专有)
import asyncioimport pytest
import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSessionfrom app.api.main import api_app
from app.core.database import Base, get_db
from main import app# 使用独立的测试数据库
# _test
# TEST_DATABASE_URL = "mysql+aiomysql://root:rootpassword@127.0.0.1:3306/test_db"
TEST_DATABASE_URL = "mysql+aiomysql://root:rootpassword@localhost:3306/media_bank"
test_engine = create_async_engine(TEST_DATABASE_URL, echo=False)
TestingSessionLocal = async_sessionmaker(bind=test_engine, expire_on_commit=False)# 初始化表结构(通常在测试套件开始时运行一次)
@pytest_asyncio.fixture(scope="session", autouse=True)
async def init_test_database():pass'''async with test_engine.begin() as conn:# 测试前:清空并重新创建所有表await conn.run_sync(Base.metadata.drop_all)await conn.run_sync(Base.metadata.create_all)yieldasync with test_engine.begin() as conn:# 测试结束后:可选清理await conn.run_sync(Base.metadata.drop_all)'''# 核心:每次测试独立的 AsyncSession,并利用外部事务自动回滚
@pytest_asyncio.fixture(scope="session")
async def db_session() -> AsyncSession:async with test_engine.connect() as connection:# 开启一个根事务transaction = await connection.begin()# 将 session 绑定到这个连接上async with TestingSessionLocal(bind=connection) as session:yield session# 测试完成后,无条件回滚!数据库不会留下任何痕迹await transaction.rollback()# 核心:异步 HTTP 客户端
@pytest_asyncio.fixture(scope="function")
async def async_client(db_session: AsyncSession):# 重写 FastAPI 的依赖项,注入带有自动回滚功能的 db_sessionasync def _get_test_db():yield db_sessionapi_app.dependency_overrides[get_db] = _get_test_db# 使用 httpx.AsyncClient 替代 TestClientasync with AsyncClient(transport=ASGITransport(app=api_app), base_url="http://127.0.0.1:8000") as client:yield clientapi_app.dependency_overrides.clear()

测试函数:

@pytest.mark.asyncio(scope="session")
async def test_get_user_by_username(db_session):'''# 1. 准备数据:利用测试 session 往数据库塞入一条测试数据mock_user = User(id=1, username="admin")db_session.add(mock_user)await db_session.commit()'''# 2. 调用我们要测试的独立函数,将测试 session 作为参数传进去user = await get_user_by_username(db=db_session, username='admin')print('user:', user)# 3. 断言结果assert user is not Noneassert user.username == "admin"

 

http://www.jsqmd.com/news/1283740/

相关文章:

  • 2026年CNC加工供应厂家怎么选 实用靠谱选型全攻略 - 热点品牌推荐
  • AP0316内置3W功放:扬声器与麦克风共腔设计的AEC与功放干扰分析
  • Python Pygame打地鼠游戏开发:面向对象设计、事件处理与多关卡实现
  • 炉石传说增强插件HsMod:终极游戏加速与个性化定制指南
  • FP6298恒压方案 vs FP7208恒流方案:美容仪控制器设计分析
  • 本地部署 AI 自动化工具 OpenClaw 2.7.9,高效解决办公重复工作
  • 2026 年舟山靠谱的矿物纤维喷涂厂家哪家强,装修降噪隔热全搞定?这玩意儿居然比传统材料还省一半成本-翰欧无机纤维喷涂 - 实业推荐官【官方】
  • 无人驾驶安全验证:方法论与实践挑战
  • FS25_AutoDrive终极指南:5分钟掌握《模拟农场25》全自动农业管理
  • 28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!
  • QT C++调用Python异常处理:PyBind11实战与跨语言编程指南
  • A-47双麦回音消除模块:主次麦空间分布与差分连接对ENC性能的影响
  • 金融舆情监测系统:多语言情感分析与实时可视化技术解析
  • 计算机毕业设计之BBS论坛系统
  • 领导力全球EMBA:民营企业家择校选择指南
  • 实测12款AI音乐工具后,我们锁定了唯一支持商用授权+无缝循环+自定义时长的3个神器
  • 声音没气场,让人一听就不信服? - 深圳市民HLL
  • 2026 年新发布:山西正规的仿古做旧青石板制造厂家推荐,谁能想到,小区铺了十年的这块石板,居然不是老古董,是这玩意儿!-高领石业青石板 - 行业推荐【认证官】
  • 开源模型微调成功率为何低于31%?——基于Hugging Face 2024 Q2真实提交日志的失败根因分析报告
  • AI原生SaaS应用的CI/CD方案设计与实践
  • MySQL数据库开发实战:从SQL语法到索引优化与性能调优
  • 机器人时间最优轨迹规划的终极方案:Ruckig完全入门指南
  • I.Ming 8.10字体发布:300+字符扩展与多语言排版技术架构深度解析
  • 解决iOS自动化测试痛点:iOS-Tagent高级功能与实用技巧
  • Code::Blocks新手必看:C/C++编译报错与警告全解析及实战解决指南
  • 注意力机制
  • 领导力全球EMBA:企业家择校选择指南
  • 5分钟快速搭建私有搜索引擎:SearXNG Docker完整指南
  • Bash Shell命令详解:从基础操作到高级脚本编写
  • Adomate 自动化营销全流程落地指南