fastapi-編寫單元測試

概述

fastapi+tortoise-orm的結構,單元測試這一塊講述的都比較不清晰,而且都只是直接丟代碼,沒有講原因。
實際上,tortoise-orm在執行的時候,只會被初始化一次,所以在單元測試之前,需要先進行一次初始化,創建一個測試數據庫,然後在測試完畢之後刪除其測試數據庫。
tortoise-orm官方的fastapi實例的測試在部分情況是無法運行的,會報錯,特別是在引入一些例如ReArq這樣的異步緩存包之後,執行就很容易報錯了。
這裏我記錄一下自己的單元測試編寫記錄

conftest

conftest.py文件主要是配置單元測試的一部分需要經常調用或者在很多測試包裏面都會執行的一些函數或方法,或者單元測試需要初始化的一些東西。
該文件必須放在根目錄。
conftest文件裏面需要創建一個初始化的方法,在pytest運行的時候先運行,將tortoise-rom連接到數據庫,然後還需要生成一個fastapi會使用的異步loop(保證數據庫和tortoise-orm在同一個異步裏面)

# conftest.py
import asyncio
import os
import pytest
from tortoise import Tortoise,  generate_schema_for_client


@pytest.fixture(scope="session")#註冊爲一個模塊,這樣這個函數只會被調用一次,其他的次數都是直接使用第一次調用的結果,功能上類似於@preporty,將這個函數註冊爲方法,然後在後面使用的時候直接在參數裏面註明就行(請參考後面)
def loop():
    loop = asyncio.get_event_loop()
    return loop


TORTOISE_ORM = {#tortoise-orm配置,用來替代代碼裏面的默認配置,除了數據庫連接需要修改,其他的一般不需要動
    "connections": {
        "default": {
            "engine": "tortoise.backends.mysql",#注意,測試數據庫如果爲memory類型,可能會導致pytest無法卡在最後無法退出(據大佬說sqlite也有這個毛病,沒試過不確定)。
            "credentials": {
                "host": "127.0.0.1",
                "port": 3306,
                "user": "root",#如果不爲root,可能會出現意想不到的bug,我爲了這個搞了一下午...
                "password": "mnbvcxz123",
                "database": "realman5",
                "echo": os.getenv("DB_ECHO") == "True",
                "maxsize": 10,
            },
        },
    },
    "apps": {
        "models": {
            "models": ["realman.models", "aerich.models", "plibs.contrib.fastapi.admin.models"],
            "default_connection": "default",
        },
    },
}


@pytest.fixture(scope="session", autouse=True)#初始化tortoise-orm的連接,autouse自動調用,啓動pytest的時候會自動調用
def initialize_tests(loop, request):
    loop.run_until_complete(Tortoise.init(config=TORTOISE_ORM,_create_db=True))
    # 創建數據庫,創建一個臨時數據庫
    loop.run_until_complete(
        generate_schema_for_client(Tortoise.get_connection("default"), safe=True)
    )
    #這裏使用回調的方式,在左右測試完畢的時候會刪除該數據庫
    # 嘗試刪除所有數據庫,在所有的數據操作完畢之後回調該方法刪除數據庫
    request.addfinalizer(lambda: loop.run_until_complete(Tortoise._drop_databases()))

tests

tests文件夾放在根目錄,裏面存放所有需要測試的文件。

創建數據

由於數據庫是臨時創建的,所以裏面必然是空的,需要手動寫入一些數據。
測試數據庫的讀寫:

#test_mysql.py
import time
from asyncio import AbstractEventLoop
from fastapi.testclient import TestClient
from realman.common import get_jwt_token
from realman.main import app
from realman.models import HelpCenter

async def write_help_center():
    await HelpCenter.create(title="測試中心", content="這是測試", category=1)

def test_writesql(loop: AbstractEventLoop):#這個loop會調用conftest裏面的loop方法生成
    loop.run_until_complete(write_help_center())

這裏建議把創建數據的操作放到之前的自動調用函數裏面去,這樣創建完數據庫可以第一時間把測試數據寫入。

測試接口

測試接口的方式,在fastapi裏面有寫的比較清楚,使用也很簡單。調用fastapi生成一個client,所有的接口訪問都走client就ok。
這裏和django挺像的,我直接放一段代碼大家就知道怎麼用了

import time
from asyncio import AbstractEventLoop
from fastapi.testclient import TestClient
from realman.main import app
from realman.models import HelpCenter

client = TestClient(app)

def test_help_center_detail():
    response = client.get("/api/help_center/detail", params={"pk": 1}, headers=get_headers())
    assert response.status_code==200
    print(...)#如果要在輸出裏面查看print打印,要調用pytest -s,

如有更好的方法,歡迎大家交流溝通

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章