33 使用测试数据库

在上一篇中,我们介绍了如何使用 pytest 进行 FastAPI 应用的测试。在进行测试时,尤其是涉及到数据库的功能时,我们需要一个快速且可控的方式来测试数据库交互。为此,我们将创建一个 测试数据库

什么是测试数据库?

测试数据库是专门用于测试目的的数据库实例,它通常与生产环境和开发环境数据库分开。通过使用测试数据库,我们可以:

  • 避免对生产数据造成影响。
  • 使测试结果独立于开发和生产环境。
  • 更容易地创建和销毁测试数据。

在本教程中,我们将使用 SQLite 作为我们的测试数据库,因为它简单且易于设置。接下来我们将展示如何将其集成到我们的 FastAPI 测试中。

设置测试数据库

首先,我们需要安装必要的依赖包。确保你的 requirements.txt 中包含以下行:

1
2
3
4
5
fastapi
pytest
httpx
sqlalchemy
databases

然后,我们可以创建一个 conftest.py 文件,来配置测试数据库。

conftest.py 示例

在项目根目录下,创建一个名为 conftest.py 的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import pytest
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from app.models import Base
from app.main import app # 确保导入你的FastAPI应用实例
import databases

# 创建一个测试数据库连接
DATABASE_URL = "sqlite+aiosqlite:///./test.db" # 使用SQLite作为测试数据库
engine = create_async_engine(DATABASE_URL, echo=True)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

@pytest.fixture(scope="session")
async def setup_database():
# 创建数据库表
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)

yield

# 在测试结束后,销毁数据库
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)

@pytest.fixture
async def db_session(setup_database):
# 创建一个新的数据库会话
async_session: AsyncSession = TestingSessionLocal()
yield async_session
await async_session.close()

这里,我们使用了 pytestfixture 来设置和清理测试数据库。setup_database fixture 会在测试会话开始时创建所有数据库表,并在测试完成后删除它们。

使用测试数据库进行测试

接下来,我们需要编写测试用例,以确保我们的 FastAPI 应用与数据库交互正常。在此例中,我们将测试一个简单的 CRUD 操作。

假设的模型和API

假设我们有一个 User 模型和相应的 FastAPI 路由。首先,我们定义模型:

1
2
3
4
5
6
7
8
9
10
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
__tablename__ = "users"

id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)

然后,我们在 FastAPI 中定义 API 路由:

1
2
3
4
5
6
7
8
9
10
11
12
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from app.database import get_db # 假设有一个获取DB的依赖函数

app = FastAPI()

@app.post("/users/", response_model=User)
async def create_user(user: User, db: Session = Depends(get_db)):
db.add(user)
await db.commit()
await db.refresh(user)
return user

编写测试用例

现在,我们来编写一个简单的测试,来验证我们的 create_user 路由。

在你的测试文件中(比如 test_api.py),添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pytest
from httpx import AsyncClient
from app.main import app
from app.models import User

@pytest.mark.asyncio
async def test_create_user(db_session):
async with AsyncClient(app=app, base_url="http://test") as client:
user_data = {"name": "Test User"}

response = await client.post("/users/", json=user_data)

assert response.status_code == 200
assert response.json()["name"] == user_data["name"]

# 验证数据库中是否插入了该用户
result = await db_session.execute(select(User).where(User.name == "Test User"))
user = result.scalars().first()
assert user is not None
assert user.name == "Test User"

在这个测试中,我们首先使用 AsyncClient 发送一个 POST 请求来创建用户。然后,我们验证响应的 status_code 和返回的数据。最后,我们通过与数据库会话的交互,检查用户是否实际被插入到测试数据库中。

总结

通过使用一个独立的测试数据库,我们可以确保我们的 FastAPI 应用在运行测试时不会影响生产数据。这种方法也提高了测试的可靠性和可维护性。接下来,在下一篇教程中,我们将讨论如何 选择 FastAPI 应用的部署方式。保持关注!

作者

IT教程网(郭震)

发布于

2024-08-17

更新于

2024-08-18

许可协议

分享转发

交流

更多教程加公众号

更多教程加公众号

加入星球获取PDF

加入星球获取PDF

打卡评论