tva
← Insights

一个 PR 中的数十个后端测试:我们的 FastAPI 测试策略

为什么在一个 PR 中

在已有代码上添加测试是一个容易被推迟的任务——"我们稍后会补测试"。将其作为一个专注的单一 PR 来处理,迫使进行系统化而不是增量式的处理。它还将测试范围讨论集中在一个地方,而不是分散在数十个功能 PR 中。

Fixture 策略

测试 fixture 设计是决定测试套件规模是否可维护的关键。我们使用分层 fixture:

@pytest.fixture(scope="session")
async def db():
    """创建一个每个测试会话使用一次的测试数据库"""
    engine = create_async_engine(TEST_DATABASE_URL)
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield engine
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)

@pytest.fixture
async def session(db):
    """每个测试一个数据库会话,在事务中包装"""
    async with AsyncSession(db) as session:
        async with session.begin():
            yield session
            await session.rollback()  # 每次测试后自动回滚

关键点:数据库在会话级别创建一次,但每个测试在事务中运行,测试后自动回滚。这使得测试相互隔离,同时避免了重复的数据库创建开销。

认证模拟

FastAPI 的依赖注入系统使认证模拟变得简单:

def override_get_current_user():
    return User(id="test-user", role="admin")

app.dependency_overrides[get_current_user] = override_get_current_user

这避免了实际 JWT 验证,而不需要模拟任何底层的认证基础设施。

测试覆盖率优先级

100% 的测试覆盖率通常不是一个有价值的目标——它优化了一个表面指标,而不是实际的测试质量。我们优先覆盖:业务逻辑(数据转换、计算)、认证和授权边界,以及已知出现过错误的代码路径。工具代码(日志记录、配置加载)覆盖优先级较低。

相关洞见

相关文章