動態

詳情 返回 返回

為什麼你的FastAPI測試覆蓋率總是低得讓人想哭? - 動態 詳情


url: /posts/985c18ca802f1b6da828b92e082b4d4e/
title: 為什麼你的FastAPI測試覆蓋率總是低得讓人想哭?
date: 2025-09-01T03:56:38+08:00
lastmod: 2025-09-01T03:56:38+08:00
author: cmdragon

summary:
FastAPI 開發中,測試環境和基礎框架的搭建至關重要。使用 pipenvpoetry 管理虛擬環境和依賴,項目結構包括應用入口、API 路由、數據模型、數據庫連接和配置文件。核心框架代碼涉及 SQLAlchemy 配置、Pydantic 配置管理和 FastAPI 入口。測試覆蓋率檢測工具配置包括 pytestcoverage.pypytest-cov,編寫測試用例並生成覆蓋率報告。優化策略包括分支覆蓋率測試、異步任務覆蓋率和目標覆蓋率報告,確保代碼質量和可維護性。

categories:

  • fastapi

tags:

  • FastAPI
  • 測試環境配置
  • 依賴管理
  • 測試覆蓋率
  • pytest
  • SQLAlchemy
  • Pydantic

<img src="https://api2.cmdragon.cn/upload/cmder/20250304_012821924.jpg" title="cmdragon_cn.png" alt="cmdragon_cn.png"/>

掃描二維碼關注或者微信搜一搜:編程智域 前端至全棧交流與成長

發現1000+提升效率與開發的AI工具和實用程序:https://tools.cmdragon.cn/

一、測試環境配置與基礎框架搭建

在 FastAPI 開發中,完善的測試環境和基礎框架是保證代碼質量和可維護性的關鍵。以下是具體實現步驟:

1.1 環境配置與依賴管理

使用 pipenvpoetry 管理虛擬環境和依賴:

# 安裝 pipenv  
pip install pipenv  

# 創建虛擬環境並安裝依賴  
pipenv install fastapi uvicorn pytest httpx pydantic==2.0.0 sqlalchemy==2.0.0

依賴説明:

  • fastapi: Web 框架核心
  • uvicorn: ASGI 服務器
  • pytest: 測試框架
  • httpx: 測試 HTTP 請求
  • pydantic: 數據驗證(v2.0 新特性支持嚴格類型校驗)
  • sqlalchemy: ORM 工具

1.2 基礎框架結構

創建項目目錄結構:

project/
├── app/
│   ├── main.py           # 應用入口
│   ├── routes/           # API 路由
│   ├── models/           # Pydantic 數據模型
│   ├── database.py       # 數據庫連接
│   └── config.py         # 配置文件
├── tests/
│   ├── conftest.py       # 測試配置
│   └── test_api.py       # API 測試用例
└── requirements.txt

1.3 核心框架代碼

database.py (SQLAlchemy 配置):

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# 依賴注入數據庫會話
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

config.py (Pydantic 配置管理):

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "FastAPI Demo"
    debug_mode: bool = False

    class Config:
        env_file = ".env"

settings = Settings()

main.py (FastAPI 入口):

from fastapi import FastAPI, Depends
from .database import get_db
from .routes import items_router
from .config import settings

app = FastAPI(title=settings.app_name)

# 掛載路由
app.include_router(items_router, prefix="/items")

@app.get("/")
async def root():
    return {"message": "Hello World"}

🔍 課後 Quiz 1

問題: 為什麼使用 yield 而不是 return 提供數據庫會話?
答案解析:
get_db 中使用 yield 實現依賴注入的生命週期管理:

  1. yield 前的代碼在請求開始時執行(創建會話)
  2. yield 後的代碼在請求結束時執行(關閉會話)
  3. 這種方式確保即使出現異常也能正確釋放資源

⚠️ 常見報錯解決方案 (1.X)

報錯: 422 Unprocessable Entity
原因: 請求體不符合 Pydantic 模型定義
解決方案:

  1. 檢查請求的 JSON 數據結構
  2. 驗證模型字段是否匹配,例如:

    class Item(BaseModel):
        name: str  # 要求必須字符串類型
        price: float
  3. 使用 curl -v 查看詳細錯誤信息

預防建議:

  • 為模型字段添加默認值,如 name: str = "default"
  • 使用 Union 支持多類型,如 price: Union[float, None] = None

二、測試覆蓋率檢測工具配置

測試覆蓋率是衡量代碼質量的核心指標。FastAPI 推薦使用:

  • pytest:測試運行器
  • coverage.py:覆蓋率檢測
  • pytest-cov:集成插件

2.1 配置 pytest

tests/conftest.py (測試依賴注入):

import pytest
from httpx import AsyncClient
from app.main import app

@pytest.fixture
async def client():
    async with AsyncClient(app=app, base_url="http://test") as ac:
        yield ac

2.2 編寫測試用例

tests/test_api.py

import pytest

# 測試 API 端點
@pytest.mark.asyncio
async def test_create_item(client):
    response = await client.post(
        "/items/",
        json={"name": "Test Item", "price": 9.99}  # 符合 Pydantic 模型
    )
    assert response.status_code == 200
    assert response.json()["name"] == "Test Item"

# 測試無效數據
@pytest.mark.asyncio
async def test_invalid_item(client):
    response = await client.post(
        "/items/",
        json={"price": "invalid"}  # 缺少必要字段 name
    )
    assert response.status_code == 422  # 觸發 Pydantic 驗證錯誤

2.3 覆蓋率檢測配置

  1. 安裝依賴:

    pipenv install coverage pytest-cov
  2. 運行測試並生成報告:

    pytest --cov=app --cov-report=html tests/
  3. 查看 HTML 報告:

    open htmlcov/index.html

2.4 持續集成集成

.github/workflows/ci.yml 中配置:

name: CI Pipeline
on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v4
    - name: Install dependencies
      run: pip install pipenv && pipenv install --dev
    - name: Run tests
      run: pytest --cov=app --cov-fail-under=80  # 要求覆蓋率≥80%

🔍 課後 Quiz 2

問題: 覆蓋率報告中 --cov-fail-under=80 參數的作用是什麼?
答案解析:
該參數設置最低覆蓋率閾值:

  1. 如果整體覆蓋率低於 80%,測試將失敗
  2. 防止未經充分測試的代碼合併到主分支
  3. 在 CI/CD 流程中強制質量門禁

⚠️ 常見報錯解決方案 (2.X)

報錯: ModuleNotFoundError: No module named 'app'
原因: 測試運行路徑錯誤
解決方案:

  1. 從項目根目錄運行測試:

    cd /project && pytest
  2. pytest.ini 中添加:

    [pytest]
    pythonpath = .

    預防建議:

  3. 使用 __init__.py 將目錄轉為 Python 包
  4. 避免在測試中硬編碼絕對路徑

三、測試覆蓋率優化策略

3.1 分支覆蓋率測試

# 測試不同業務分支
@pytest.mark.parametrize("price, discount", [
    (100, 10),  # 正常折扣
    (50, 0),    # 無折扣
    (30, -5)    # 無效折扣
])
async def test_discount_logic(client, price, discount):
    response = await client.post(
        "/items/",
        json={"name": "Test", "price": price, "discount": discount}
    )
    if discount < 0: 
        assert response.status_code == 400  # 驗證業務規則
    else:
        assert response.status_code == 200

3.2 異步任務覆蓋率

對於後台異步任務:

from fastapi import BackgroundTasks

async def notify_admins(email: str):
    # 模擬發送郵件
    print(f"Sending email to {email}")

@app.post("/report")
async def create_report(background_tasks: BackgroundTasks):
    background_tasks.add_task(notify_admins, "admin@example.com")
    return {"message": "Report scheduled"}

測試策略:

# Mock 後台任務
from unittest.mock import MagicMock

@pytest.mark.asyncio
async def test_background_task(client):
    app.notify_admins = MagicMock()  # 替換為 Mock 函數
    response = await client.post("/report")
    app.notify_admins.assert_called_once_with("admin@example.com")

3.3 目標覆蓋率報告

----------- coverage: platform linux -----------
Name                  Stmts   Miss  Cover
-----------------------------------------
app/__init__.py          0      0   100%
app/main.py             15      0   100%
app/routes.py           20      1    95%   # 缺失分支
-----------------------------------------
TOTAL                   35      1    97%

 graph TD
A[啓動測試] --> B[pytest 執行用例]
B --> C{覆蓋率採集}
C -->|SQLAlchemy| D[數據庫操作]
C -->|Pydantic| E[數據驗證]
C -->|BackgroundTasks| F[異步任務]
D --> G[生成報告]
E --> G
 F --> G

餘下文章內容請點擊跳轉至 個人博客頁面 或者 掃碼關注或者微信搜一搜:編程智域 前端至全棧交流與成長,閲讀完整的文章:為什麼你的FastAPI測試覆蓋率總是低得讓人想哭?

<details>
<summary>往期文章歸檔</summary>

  • 如何讓FastAPI測試不再成為你的噩夢? - cmdragon's Blog
  • FastAPI測試環境配置的秘訣,你真的掌握了嗎? - cmdragon's Blog
  • 全鏈路追蹤如何讓FastAPI微服務架構的每個請求都無所遁形? - cmdragon's Blog
  • 如何在API高併發中玩轉資源隔離與限流策略? - cmdragon's Blog
  • 任務分片執行模式如何讓你的FastAPI性能飆升? - cmdragon's Blog
  • 冷熱任務分離:是提升Web性能的終極秘籍還是技術噱頭? - cmdragon's Blog
  • 如何讓FastAPI在百萬級任務處理中依然遊刃有餘? - cmdragon's Blog
  • 如何讓FastAPI與消息隊列的聯姻既甜蜜又可靠? - cmdragon's Blog
  • 如何在FastAPI中巧妙實現延遲隊列,讓任務乖乖等待? - cmdragon's Blog
  • FastAPI的死信隊列處理機制:為何你的消息系統需要它? - cmdragon's Blog
  • 如何讓FastAPI任務系統在失敗時自動告警並自我修復? - cmdragon's Blog
  • 如何用Prometheus和FastAPI打造任務監控的“火眼金睛”? - cmdragon's Blog
  • 如何用APScheduler和FastAPI打造永不宕機的分佈式定時任務系統? - cmdragon's Blog
  • 如何在 FastAPI 中玩轉 APScheduler,讓任務定時自動執行? - cmdragon's Blog
  • 定時任務系統如何讓你的Web應用自動完成那些煩人的重複工作? - cmdragon's Blog
  • Celery任務監控的魔法背後藏着什麼秘密? - cmdragon's Blog
  • 如何讓Celery任務像VIP客户一樣享受優先待遇? - cmdragon's Blog
  • 如何讓你的FastAPI Celery Worker在壓力下優雅起舞? - cmdragon's Blog
  • FastAPI與Celery的完美邂逅,如何讓異步任務飛起來? - cmdragon's Blog
  • FastAPI消息持久化與ACK機制:如何確保你的任務永不迷路? - cmdragon's Blog
  • FastAPI的BackgroundTasks如何玩轉生產者-消費者模式? - cmdragon's Blog
  • BackgroundTasks 還是 RabbitMQ?你的異步任務到底該選誰? - cmdragon's Blog
  • BackgroundTasks與Celery:誰才是異步任務的終極贏家? - cmdragon's Blog
  • 如何在 FastAPI 中優雅處理後台任務異常並實現智能重試? - cmdragon's Blog
  • BackgroundTasks 如何巧妙駕馭多任務併發? - cmdragon's Blog
  • 如何讓FastAPI後台任務像多米諾骨牌一樣井然有序地執行? - cmdragon's Blog
  • FastAPI後台任務:是時候讓你的代碼飛起來了嗎? - cmdragon's Blog
  • FastAPI後台任務為何能讓郵件發送如此絲滑? - cmdragon's Blog
  • FastAPI的請求-響應週期為何需要後台任務分離? - cmdragon's Blog
  • 如何在FastAPI中讓後台任務既高效又不會讓你的應用崩潰? - cmdragon's Blog
  • FastAPI後台任務:異步魔法還是同步噩夢? - cmdragon's Blog
  • 如何在FastAPI中玩轉Schema版本管理和灰度發佈? - cmdragon's Blog
  • FastAPI的查詢白名單和安全沙箱機制如何確保你的API堅不可摧? - cmdragon's Blog
  • 如何在 FastAPI 中玩轉 GraphQL 性能監控與 APM 集成? - cmdragon's Blog
  • 如何在 FastAPI 中玩轉 GraphQL 和 WebSocket 的實時數據推送魔法? - cmdragon's Blog
  • 如何在FastAPI中玩轉GraphQL聯邦架構,讓數據源手拉手跳探戈? - cmdragon's Blog
  • GraphQL批量查詢優化:DataLoader如何讓數據庫訪問速度飛起來? - cmdragon's Blog
    </details>

<details>
<summary>免費好用的熱門在線工具</summary>

  • ASCII字符畫生成器 - 應用商店 | By cmdragon
  • JSON Web Tokens 工具 - 應用商店 | By cmdragon
  • Bcrypt 密碼工具 - 應用商店 | By cmdragon
  • GIF 合成器 - 應用商店 | By cmdragon
  • GIF 分解器 - 應用商店 | By cmdragon
  • 文本隱寫術 - 應用商店 | By cmdragon
  • CMDragon 在線工具 - 高級AI工具箱與開發者套件 | 免費好用的在線工具
  • 應用商店 - 發現1000+提升效率與開發的AI工具和實用程序 | 免費好用的在線工具
  • CMDragon 更新日誌 - 最新更新、功能與改進 | 免費好用的在線工具
  • 支持我們 - 成為贊助者 | 免費好用的在線工具
  • AI文本生成圖像 - 應用商店 | 免費好用的在線工具
  • 臨時郵箱 - 應用商店 | 免費好用的在線工具
  • 二維碼解析器 - 應用商店 | 免費好用的在線工具
  • 文本轉思維導圖 - 應用商店 | 免費好用的在線工具
  • 正則表達式可視化工具 - 應用商店 | 免費好用的在線工具
  • 文件隱寫工具 - 應用商店 | 免費好用的在線工具
  • IPTV 頻道探索器 - 應用商店 | 免費好用的在線工具
  • 快傳 - 應用商店 | 免費好用的在線工具
  • 隨機抽獎工具 - 應用商店 | 免費好用的在線工具
  • 動漫場景查找器 - 應用商店 | 免費好用的在線工具
  • 時間工具箱 - 應用商店 | 免費好用的在線工具
  • 網速測試 - 應用商店 | 免費好用的在線工具
  • AI 智能摳圖工具 - 應用商店 | 免費好用的在線工具
  • 背景替換工具 - 應用商店 | 免費好用的在線工具
  • 藝術二維碼生成器 - 應用商店 | 免費好用的在線工具
  • Open Graph 元標籤生成器 - 應用商店 | 免費好用的在線工具
  • 圖像對比工具 - 應用商店 | 免費好用的在線工具
  • 圖片壓縮專業版 - 應用商店 | 免費好用的在線工具
  • 密碼生成器 - 應用商店 | 免費好用的在線工具
  • SVG優化器 - 應用商店 | 免費好用的在線工具
  • 調色板生成器 - 應用商店 | 免費好用的在線工具
  • 在線節拍器 - 應用商店 | 免費好用的在線工具
  • IP歸屬地查詢 - 應用商店 | 免費好用的在線工具
  • CSS網格佈局生成器 - 應用商店 | 免費好用的在線工具
  • 郵箱驗證工具 - 應用商店 | 免費好用的在線工具
  • 書法練習字帖 - 應用商店 | 免費好用的在線工具
  • 金融計算器套件 - 應用商店 | 免費好用的在線工具
  • 中國親戚關係計算器 - 應用商店 | 免費好用的在線工具
  • Protocol Buffer 工具箱 - 應用商店 | 免費好用的在線工具
  • IP歸屬地查詢 - 應用商店 | 免費好用的在線工具
  • 圖片無損放大 - 應用商店 | 免費好用的在線工具
  • 文本比較工具 - 應用商店 | 免費好用的在線工具
  • IP批量查詢工具 - 應用商店 | 免費好用的在線工具
  • 域名查詢工具 - 應用商店 | 免費好用的在線工具
  • DNS工具箱 - 應用商店 | 免費好用的在線工具
  • 網站圖標生成器 - 應用商店 | 免費好用的在線工具
  • XML Sitemap

</details>

user avatar ljc1212 頭像 zjkal 頭像 tugraph 頭像 shuirongshui 頭像 shawn_5dd516205b8bd 頭像
點贊 5 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.