<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          FastAPI 之自動化測試數(shù)據(jù)庫接口

          共 3348字,需瀏覽 7分鐘

           ·

          2022-01-02 14:51

          今天的文章分享如下在 FastAPI 框架下,使用 pytest 來自動化測試數(shù)據(jù)庫相關(guān)的接口,文章的最后給出全部代碼。

          最近越來越喜歡使用 FastAPI 來寫后端服務(wù)了,因為它是 Python 領(lǐng)域性能最好的 Web 框架,它專注于提供高性能的 Web API,其他方面并不限制你的手腳,可以隨意使用你喜歡的三方庫,這點類似于 Flask,可以量身定制你的后端架構(gòu),以滿足自己的需求。

          需要說明的是,后端服務(wù)基本是離不開關(guān)系型數(shù)據(jù)庫的,我之前是使用 Django,Django 的 ORM 太優(yōu)秀了,以至于我從 Django 轉(zhuǎn) FastAPI 有點很不適應(yīng)。在 ORM 領(lǐng)域,可以說除了 Django 的 ORM,就是 SQLAlchemy 了。所以不用 Django,就必須會用 SQLAlchemy,要快速了解,看看廖雪峰的官方網(wǎng)站的使用 SQLAlchemy[1] 來快速入門。

          FastAPI 涉及數(shù)據(jù)庫的接口寫起來并不難,跟著官方文檔sql_databases[2],5 分鐘,我們就可以生成關(guān)于數(shù)據(jù)庫的增刪改查的 Restful 風(fēng)格的 API,難的是如何自動化的測試,

          通常情況下,我們會使用 pytest 進(jìn)行自動化單元測試,根據(jù)數(shù)據(jù)庫的記錄數(shù)來斷言,但是,每測試一次,數(shù)據(jù)庫中的記錄就保存了下來,你下次測試時如果不手動清理,那測試仍然可能失敗。

          那怎么解決呢?

          那就是利用數(shù)據(jù)庫的回滾功能,會改變數(shù)據(jù)庫記錄的接口測試完成后讓事務(wù)回滾,這樣每次測試完成后,數(shù)據(jù)庫的記錄數(shù)是不變的,每次運行 pytest,數(shù)據(jù)庫的記錄數(shù)是不變的,這樣就可以進(jìn)行自動化測試。

          要想實現(xiàn)這一點,我們需要借助于 pytest 的 fixture 功能。

          pytest.fixture 是一個裝飾器,用于聲明函數(shù)是一個 fixture。如果測試函數(shù)的參數(shù)列表中包含 fixture 名,那么 pytest 會檢測到,并在測試函數(shù)運行之前執(zhí)行 fixture。

          比如:

          import?pytest

          @pytest.fixture()
          def?some_data():
          ????return?42

          def?test_some_data(some_data):
          ????assert?some_data==42

          fixture 包含一個 scope 的可選參數(shù),用于控制 fixture 執(zhí)行配置和銷毀邏輯的頻率:

          • scope='function' 函數(shù)級別的 fixture 每個測試函數(shù)只運行一次。配置代碼在測試用例運行之前運行,銷毀代碼在測試用例運行之后執(zhí)行。function 是 fixture 參數(shù)的默認(rèn)值。
          • scope='class' 類級別的 fixture 每個測試類只運行一次,不管測試類中有多少個類方法都可以共享這個 fixture
          • scope='module' 模塊級別的 fixture 每個模塊只運行一次,不管模塊里有多少個測試函數(shù),類方法或其他 fixture 都可以共享這個fixture
          • scope='session' 會話級別的 fixture 每次會話只運行一次。一次 pytest 會話中的所有測試函數(shù)、方法都可以共享這個 fixture

          比如說讓數(shù)據(jù)庫回滾的,我們就可以寫一個這樣的 fixture:

          @pytest.fixture(scope="function")
          def?db(db_engine):
          ????connection?=?db_engine.connect()
          ????#?begin?a?non-ORM?transaction
          ????connection.begin()
          ????#?bind?an?individual?Session?to?the?connection
          ????db?=?Session(bind=connection)
          ????#?db?=?Session(db_engine)
          ????app.dependency_overrides[get_db]?=?lambda:?db
          ????yield?db
          ????db.rollback()
          ????connection.close()

          當(dāng)然還有很多 fixture,比如說創(chuàng)建數(shù)據(jù)庫引擎:

          @pytest.fixture(scope="session")
          def?db_engine():
          ????engine?=?create_engine(SQLALCHEMY_DATABASE_URL)
          ????if?not?database_exists:
          ????????create_database(engine.url)

          ????Base.metadata.create_all(bind=engine)
          ????yield?engine

          再比如,在測試前,數(shù)據(jù)庫中先插入 2 條數(shù)據(jù):

          @pytest.fixture
          def?items(db):
          ????create_item(db,?schemas.ItemCreate(title="item?1"))
          ????create_item(db,?schemas.ItemCreate(title="item?2"))

          把這些 fixture 函數(shù)放在文件名conftest.py 中,pytest 會自動讀取并執(zhí)行。至于為什么放在 conftest.py中,請查閱 pytest 文檔,這里不展開,?

          接下來,利用這些 fixture,編寫單元測試用例,一個示例如下:

          from?fastapi.testclient?import?TestClient
          from?.?import?crud
          from?.main?import?app

          def?test_post_items(db):
          ????client?=?TestClient(app)
          ????client.post("/items/",?json={"title":?"Item?1"})
          ????client.post("/items/",?json={"title":?"Item?2"})
          ????client.post("/items/",?json={"title":?"Item?3"})

          ????items?=?crud.get_items(db)
          ????assert?len(items)?==?3


          def?test_list_items(items,?client):
          ????response?=?client.get("/items")
          ????assert?len(response.json())?==?2

          其中 test_post_items,測試的是提交了 3 個數(shù)據(jù),然后斷言數(shù)據(jù)庫中的記錄數(shù)為 3。test_list_items 有個參數(shù)是 items,會調(diào)用之前的 fixture,提前往數(shù)據(jù)庫插入了 2 條記錄,因此斷言記錄數(shù)為 2。

          每個測試函數(shù)執(zhí)行時互不影響,執(zhí)行完成后,數(shù)據(jù)庫都會回滾,測試前 items 是空的,測試之后 表仍然是空的,這樣就可以自動進(jìn)行數(shù)據(jù)庫的測試了。

          完整代碼

          不能選擇 sqlite 數(shù)據(jù)庫進(jìn)行測試,因為它不支持并發(fā)訪問。

          代碼的數(shù)據(jù)庫配置為 mysql,用戶名、密碼、數(shù)據(jù)庫名請自行修改后執(zhí)行。

          完整代碼公眾號「Python七號」回復(fù)「數(shù)據(jù)庫測試」獲取。

          最后的話

          本文分享了如下在 FastAPI 框架下,使用 pytest 來自動化測試數(shù)據(jù)庫相關(guān)的接口,希望對你的單元測試技能有所幫助。如果有幫助,請點點贊、在看、關(guān)注支持。如果有問題,可以留言討論哈。

          參考資料

          [1]

          使用 SQLAlchemy: https://www.liaoxuefeng.com/wiki/1016959663602400/1017803857459008

          [2]

          sql_databases: https://fastapi.tiangolo.com/tutorial/sql-databases/


          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色小电影在线免费观看 | 天天综合~91 | 亚州高清在线 | 久久亚洲AV成人无码国产精品 | 国家一级黄色片 |