【Django】-9- 單元測試和集成測試(上)

一、Django 項目單元 & 集成測試準備 👇

依賴安裝(給項目裝 “測試小幫手”🍼)

pdm add -d black isort flake8 pytest pytest-django pytest-coverage  

👉 這行命令像在給項目 “采購” 測試工具:

  • black?? 自動格式化代碼,讓代碼整齊得像排好隊的小士兵
  • isort?🧹 幫你把 import 語句整理得明明白白
  • flake8?🔍 像代碼 “小偵探”,揪出語法和風格問題
  • pytest?🧪 單元測試 “大主角”,跑測試用例超好用
  • pytest-django?🐍+🧪 讓 pytest 能和 Django 好好 “交朋友”,測試 Django 項目
  • pytest-coverage?📊 看看測試覆蓋了多少代碼,心里有底

?

配置文件(給工具們定 “小規矩”📜)

1.?.flake8(flake8 的 “小手冊”)
[flake8]  
exclude = venv  # 告訴 flake8 別去碰 venv 文件夾~🚫  
extend-ignore = E501  # 放寬點啦,忽略行太長的報錯(E501)🙈  
2.?pytest.ini(pytest 的 “劇本”)
[pytest]  
DJANGO_SETTINGS_MODULE = Tesla.settings  # 告訴 pytest 用哪個 Django 配置??  
python_files = tests.py test_*.py  # 哪些文件算測試文件呀?找 tests.py 和 test_開頭的~🔍  

測試用例(給項目 “模擬闖關”🎮)

根據我們的業務邏輯代碼進行分析~

?

1. 注冊功能 📝
  • 允許匿名訪問 👻(游客也能注冊!)
  • URL:http://127.0.0.1:8000/accounts/register?🔗
    • GET:返回 HTML 頁面~像打開注冊 “小窗口”🖥?
    • POST:提交 JSON 數據,還要驗證:
      • 用戶名不能為空 ?(空用戶名像沒名字的小幽靈,不行!)
      • 密碼不能為空 ?(沒密碼咋保護自己~)
      • 兩次密碼得一樣 🔄(不然自己都記混啦)
      • 密碼長度≥6 位 📏(太短不安全呀)
      • 用戶名不能重復 👥(不能撞名呀)
      • 都對的話,返回 “注冊成功”🎉

?

2. 登錄功能 🔑
  • 允許匿名訪問 👻(游客也能登錄頁逛逛)
  • URL:http://127.0.0.1:8000/accounts/login/?🔗
    • GET:返回登錄 HTML 頁面 🖥?
    • POST:提交表單,還要驗證:
      • 用戶名不能為空 ?(沒用戶名咋找賬號~)
      • 密碼不能為空 ?(沒密碼進不去呀)
      • 用戶名、密碼得對 ?(不然進錯家門啦)

?

3. 提交反饋 📮
  • 不允許匿名訪問 🔒(得登錄才能反饋!)
  • URL:http://127.0.0.1:8000/beifan/submit?🔗
    • GET:返回 HTML 頁面 🖥?
    • POST:提交 JSON 數據,還要驗證:
      • 數據能存到數據庫里 🗄?(像把信放進郵箱~)
      • 數據和用戶關聯上 👤(誰發的反饋要記好)
      • 同一用戶不能重復發 🔄(別刷屏呀~)

4. 反饋結果 🔍
  • 允許匿名訪問 👻(誰都能看看結果)
  • URL:http://127.0.0.1:8000/beifan/result?🔗
  • 不管 GET/POST,都返回 HTML 頁面 🖥?(看看反饋結果啥樣~)

二、HttpResponse

數據結構角度

HttpResponse定義了一系列屬性和方法來管理響應相關的數據。

  • 屬性方面
    • content:以字節串形式存儲響應的主體內容,比如返回的 HTML 頁面內容、JSON 數據經過編碼后的字節串等。例如返回一個簡單 HTML 頁面,這個 HTML 文本內容最終會編碼后存到content中。
    • status_code:記錄 HTTP 響應狀態碼,像常見的200(請求成功)、404(頁面未找到)、500(服務器內部錯誤)等,通過這個屬性可以讓客戶端快速知曉請求處理的結果狀態。
    • headers:是一個類似字典的數據結構,用來存放 HTTP 響應頭信息,比如Content - Type(指定響應內容的類型,像text/html表示 HTML 頁面,application/json表示 JSON 數據)、Content - Length(響應內容的長度)等。
  • 方法方面
    • 它提供了一些方法來操作響應數據,比如__setitem__方法(可以像操作字典一樣response['key'] = 'value'),用于設置響應頭信息。

?

面向對象角度

HttpResponse類遵循面向對象編程范式,通過封裝、繼承和多態等特性,來實現對 HTTP 響應的管理和擴展:

  • 封裝:把與 HTTP 響應相關的各種信息(內容、狀態碼、響應頭)和操作(設置響應頭、獲取內容等)封裝在一個類中,提供了統一且便捷的接口來處理響應。比如在視圖函數中,只需要創建HttpResponse實例并設置相關屬性,就能輕松構建一個完整的 HTTP 響應。
  • 繼承:Django 提供了一些HttpResponse的子類,如HttpResponseRedirect(用于重定向,默認狀態碼為302)、JsonResponse(專門用于返回 JSON 數據,自動設置Content - Typeapplication/json?) 。這些子類繼承了HttpResponse的基本屬性和方法,并根據自身功能需求進行了擴展和定制。
  • 多態:在 Django 的視圖函數返回機制中,無論是返回HttpResponse對象還是它的子類對象,都遵循統一的規則(都被視為合法的響應返回值),這體現了多態性。視圖函數根據業務邏輯的不同,靈活返回不同類型的響應對象,而 Django 的請求處理機制都能正確處理并發送給客戶端。

?

Web 開發流程角度

在 Django 應用處理 HTTP 請求的流程中,HttpResponse是請求處理結果的最終承載者:

  • 當客戶端發起一個 HTTP 請求到 Django 服務器,Django 會根據 URL 配置找到對應的視圖函數進行處理。
  • 視圖函數在處理完業務邏輯(如查詢數據庫、進行數據計算等)后,需要構建一個響應返回給客戶端,此時就會創建HttpResponse對象(或者它的子類對象),將處理結果填充到響應對象的相關屬性中(如設置響應內容、狀態碼、響應頭)。
  • 最后,Django 的請求處理機制會將這個HttpResponse對象轉換為符合 HTTP 協議規范的格式,通過網絡發送給客戶端,客戶端再根據響應信息進行相應的展示或處理(如瀏覽器渲染 HTML 頁面、解析 JSON 數據等) 。

總之,HttpResponse類是 Django 構建和管理 HTTP 響應的核心組件,通過數據結構、面向對象編程以及在 Web 開發流程中的關鍵作用,實現了從服務器端到客戶端的響應信息傳遞。

三、測試HTTP請求?

先測試一個簡單的登錄視圖的get請求(返回一個html頁面)

from django.test.client import Clientimport pytest@pytest.fixture
def client() -> Client:return Client()def test_register_get(client: Client):resp: HttpResponse = client.get("/accounts/register")assert resp.status_code == 200html = resp.content.decode()assert "html" in htmlassert "用戶名" in htmlassert "密碼" in htmlassert "確認密碼" in html

?

1. 引入工具:from django.test.client import Client

👉?作用:從 Django 測試工具里,把「發 HTTP 請求的小助手?Client」請進來~
👀 為啥?
Django 專門給咱準備了?Client?類,用來模擬瀏覽器發請求(比如 GET、POST),測試咱的視圖函數 / 接口。就像給代碼一個 “虛擬小瀏覽器”,不用真的開瀏覽器,也能測試網頁 / 接口響不響應~

?

2. fixture 魔法:@pytest.fixture?+?def client() -> Client:

@pytest.fixture  
def client() -> Client:  return Client()  

👉?作用:用 pytest 的?fixture,創建一個可復用的 “發請求工具”,叫?client
👀 為啥這么寫?

  • @pytest.fixture?是 pytest 的 “魔法標記”🧙,標記后,這個?client?函數就變成了一個 “工具工廠”,其他測試函數要用的時候,直接當參數傳進去就行!
  • return Client():每次調用?client,都會新建一個?Client?實例(也就是新的 “虛擬小瀏覽器”),保證測試之間互不干擾~

?

3. 測試用例:def test_register_get(client: Client):

👉?作用:定義一個測試用例,名字叫?test_register_get,專門測試注冊頁面的 GET 請求
👀 為啥參數是?client: Client
因為上面用?@pytest.fixture?標記了?client,pytest 會自動把?Client?實例傳進來,供這個測試用例使用!相當于 “自動給你遞上小瀏覽器,不用自己手動創建啦”~

?

4. 發請求:resp: HttpResponse = client.get("/accounts/register")

👉?作用:用?client(虛擬小瀏覽器),發一個?GET 請求?到?/accounts/register(注冊頁面的 URL),然后把服務器返回的響應存到?resp?里~
👀 為啥這么寫?
模擬用戶在瀏覽器里輸入?http://.../accounts/register?訪問注冊頁的行為。client.get(...)?就是幫我們發 GET 請求的 “快捷方式”,不用真的啟動瀏覽器~

?

5. 斷言狀態碼:assert resp.status_code == 200

👉?作用:檢查服務器返回的狀態碼是不是?200200?代表 “請求成功”,網頁正常返回啦~)
👀 為啥要斷言?
測試的核心!如果狀態碼不是?200(比如?404?找不到頁面、500?服務器報錯),說明注冊頁面可能有問題,測試就會 “失敗”,提醒咱去修~

?

6. 解析響應內容:html = resp.content.decode()

👉?作用:把響應的二進制內容(resp.content)轉換成字符串(decode()?解碼),方便后面檢查頁面里有沒有我們要的內容~
👀 為啥要解碼?

網絡編程(發送和接收網絡數據包)的HttpResponse是字節流,二進制數據。
resp.content?存的是二進制數據(像?b'<html>...'),轉成字符串(html)后,才能用字符串的方法(比如?in?關鍵字)檢查內容~

?

7. 檢查頁面內容:一堆?assert

assert "html" in html  
assert "用戶名" in html  
assert "密碼" in html  
assert "確認密碼" in html  

👉?作用:確認返回的 HTML 里,包含 “html”“用戶名”“密碼”“確認密碼” 這些關鍵字~
👀 為啥要檢查?
保證注冊頁面的 HTML 里,確實有這些表單字段(用戶名、密碼輸入框)。如果哪天代碼不小心把這些字段刪了,測試就會失敗,提醒咱 “注冊頁面不對啦!”

?

四、測試DB數據庫?

?

🌟 user?fixture —— 提前造個 “測試用戶”

@pytest.fixture()  
def user(_django_db_helper):  new_user = User.objects.create_user(  username='test_user',  email='test_user@qq.com',  password='test_user_pass',  )  return new_user  
逐行拆解
  • @pytest.fixture()

    • pytest 的 “魔法標記”🧙,標記后,user?就變成一個可復用的 “工具函數”,其他測試用例要用時,直接傳參即可!
    • 作用:提前幫你在數據庫里造一個測試用戶,不用每次測試都手動創建啦~
  • def user(_django_db_helper):

    • _django_db_helper?是 pytest-django 提供的 “數據庫小助手”,會自動幫你初始化、清理數據庫,保證測試間互不干擾~
    • 函數名?user?是你給這個 “造用戶工具” 起的名字,方便其他測試用例調用~
  • new_user = User.objects.create_user(...)

    • 調用 Django 的?create_user?方法,在數據庫里實際創建一個用戶(用戶名、郵箱、密碼都是測試用的假數據~)
    • 相當于:“嘿,數據庫~ 幫我塞一條用戶數據,測試時要用!”
  • return new_user

    • 把剛創建的用戶對象返回,其他測試用例如果用了這個?user?fixture,就能直接拿到這個 “測試用戶” 啦~

?

🌟 參數化測試 —— 批量測 “注冊場景”

這部分是用?@pytest.mark.parametrize?批量測試不同注冊情況(用戶名空、密碼不一致、注冊成功等),超高效!

@pytest.mark.parametrize(  "data, code, msg",  [  ({"username": ""}, -1, "username 不能為空"),  # 用戶名空  ({"password_confirm": "2"}, -2, "兩次密碼輸入不一致"),  # 密碼不一致  ({"username": "test_user_beifan"}, 0, "注冊成功"),  # 注冊成功  ]  
)  
def test_register_post(user, client, data, code, msg):  # 發 POST 請求測試注冊  resp = client.post(  "/accounts/register",  data=data,  content_type="application/json"  )  # 解析響應  html = resp.content.decode()  resp_json = json.loads(html)  # 斷言響應是否符合預期  assert resp_json["code"] == code  assert resp_json["msg"] == msg  

這里的data有簡化省略了其他的鍵值對?

逐行拆解
  • @pytest.mark.parametrize("data, code, msg", [...])

    • pytest 的 “參數化魔法”🪄!括號里的?"data, code, msg"?是 “參數名”,后面的列表是 “參數值組合”。
    • 作用:批量生成測試用例,列表里每一個元組,都會對應一條測試用例~ 比如:
      • 第 1 組:data?是?{"username": ""}(用戶名空),預期?code=-1msg="username 不能為空"
      • 第 2 組:data?是?{"password_confirm": "2"}(密碼不一致),預期?code=-2msg="兩次密碼輸入不一致"
      • 第 3 組:data?是?{"username": "test_user_beifan"}(合法數據),預期?code=0msg="注冊成功"
  • def test_register_post(user, client, data, code, msg):

    • 測試用例函數,參數里:
      • user:就是圖 1 里的?user?fixture,會自動傳入 “測試用戶”(如果需要的話~)
      • client:Django 測試客戶端(圖 1 里講過的 “虛擬小瀏覽器”)
      • data, code, msg:來自?@pytest.mark.parametrize?的參數,每組數據都會跑一次測試~
  • resp = client.post(...)

    • 用?client(虛擬小瀏覽器)發一個?POST 請求?到?/accounts/register(注冊接口),還帶了?data(請求體)和?content_type="application/json"(告訴服務器,我發的是 JSON 數據喲~)
  • html = resp.content.decode()?→?resp_json = json.loads(html)

    • 把響應的二進制內容(resp.content)解碼成字符串(html),再轉成 JSON(resp_json),方便斷言~
  • assert resp_json["code"] == code?→?assert resp_json["msg"] == msg

    • 檢查響應的?code?和?msg?是否符合預期~ 比如:
      • 用戶名空時,code?應該是?-1msg?是?username 不能為空
      • 注冊成功時,code?是?0msg?是?注冊成功

?

🌟 數據庫斷言 —— 注冊成功后,用戶真的 “入庫” 了嗎?

這部分是測試 “注冊成功后,數據庫用戶數量是否變化”,保證代碼真的把用戶數據存到數據庫啦~

def test_register_post(user, client, data, code, msg):  # 1. 發請求前,先查數據庫用戶數量  user_list = list(User.objects.all())  user_count = len(user_list)  assert user_count == 1  # 假設測試前只有 1 個用戶(圖 1 里的 test_user)  # 2. 發 POST 請求測試注冊  resp = client.post(...)  # (和之前一樣,發請求、解析響應)  # 3. 斷言響應是否符合預期(code、msg)  assert resp_json["code"] == code  assert resp_json["msg"] == msg  # 4. 如果注冊成功(code == 0),再查數據庫用戶數量  if code == 0:  user_list = list(User.objects.all())  user_count = len(user_list)  assert user_count == 2  # 注冊成功后,應該新增 1 個用戶 → 總數 2  
逐行拆解
  • user_list = list(User.objects.all())?→?user_count = len(user_list)

    • 發請求,先查數據庫里的所有用戶,數一下有多少個(user_count)。
    • 假設測試環境里,一開始只有圖 1 里創建的?test_user,所以?user_count == 1
  • assert user_count == 1

    • 確保測試前數據庫狀態 “干凈”,只有 1 個測試用戶,避免其他數據干擾測試結果~
  • if code == 0:

    • code == 0?代表 “注冊成功”,這時需要再查數據庫,確認用戶真的新增了!
  • user_list = list(User.objects.all())?→?user_count = len(user_list)

    • 發請求,再次查數據庫用戶數量。
  • assert user_count == 2

    • 注冊成功的話,用戶數量應該從?1?變成?2(原來的?test_user?+ 新注冊的用戶)。
    • 相當于:“嘿,數據庫~ 注冊成功后,用戶是不是真的存進來啦?數量對不對呀?”

?

🌈 整體流程總結

  1. 造用戶:用?@pytest.fixture?提前在數據庫造一個?test_user,當 “測試種子”。
  2. 批量測注冊:用?@pytest.mark.parametrize?批量測試各種注冊場景(用戶名空、密碼錯、注冊成功)。
  3. 發請求:用?client.post?模擬瀏覽器發注冊請求,看服務器咋響應。
  4. 斷言響應:檢查返回的?code?和?msg?是否符合預期(比如注冊成功時?code=0)。
  5. 數據庫校驗:注冊成功后,再查數據庫用戶數量,確保真的新增了用戶~

user 固件也就是說意義在于數據庫的初始化,管理 驗證是否用戶名重復

1. 🛠? 幫數據庫 “熱熱身”

user?fixture 里的?User.objects.create_user(...)?一執行,就像給數據庫發了條消息:“喂~ 準備好啦,要開始測試咯!”
Django 會因此自動完成數據庫連接、創建測試表等一系列準備工作,避免測試時出現 “數據庫還沒啟動” 的尷尬錯誤~ 就像玩游戲前先加載地圖,不然點 “開始” 會卡住呀!

?

2. 🆚 提供 “參照物” 方便驗證

比如測試 “用戶名不能重復” 時,user?就像一個 “標桿用戶”🆔:

  • 它的用戶名是?test_user,已經存在于數據庫里(先建一個user數據,所以后面的斷言是1->2)
  • 當你用同樣的用戶名?test_user?去注冊時,就能驗證系統會不會報錯 “用戶名已存在”
  • 如果沒有這個 “參照物”,數據庫空空如也,根本測不出 “重復注冊” 的邏輯對不對呀~

所以哪怕?user?沒在代碼里被直接 “點名”,它也是測試里的 “幕后功臣”🌟:既讓數據庫準備好工作,又提供了關鍵的 “對比數據”,保證各種注冊場景都能被準確測試到~

?

Django 測試中通過?user?fixture 自動完成數據庫連接的過程

?

🌱 第一步:pytest-django?的 “數據庫開關”

user?fixture 里有?User.objects.create_user(...)?這行代碼 —— 它要往數據庫里寫數據,這就像給?pytest-django?遞了一張 “需要數據庫” 的門票🎫。

pytest-django?看到這張 “門票” 后,會自動觸發一個核心機制:啟用數據庫連接
(如果測試里完全用不到數據庫操作,pytest-django?會默認 “關閉” 數據庫,讓測試跑得更快~)

?

🛠? 第二步:創建 “臨時測試數據庫”

為了不污染你的真實數據庫(比如開發環境的?db.sqlite3),pytest-django?會偷偷做一件事:
自動創建一個全新的臨時數據庫(名字通常是?test_你的數據庫名,比如?test_myproject)。

這個臨時數據庫就像一個 “一次性舞臺”:

  • 結構和你的真實數據庫一模一樣(表、字段都照著抄)
  • 但里面的數據是干凈的,專門給測試用
  • 測試結束后會自動刪除,不會留下任何痕跡~

?

🔗 第三步:自動連接到臨時數據庫

Django 的核心配置里有?DATABASES?選項(在?settings.py?里),比如:

DATABASES = {  'default': {  'ENGINE': 'django.db.backends.sqlite3',  'NAME': BASE_DIR / 'db.sqlite3',  # 真實數據庫  }  
}  

當?pytest-django?檢測到需要數據庫時,會自動 “替換” 這個配置:
把?NAME?改成臨時數據庫的路徑(比如?test_db.sqlite3),然后調用 Django 內置的?connection?模塊,建立和這個臨時數據庫的連接。

這一步就像:
你本來要去 “正式餐廳”(真實數據庫),但測試時被悄悄引導到了 “隔壁的臨時分店”(臨時數據庫),地址變了,但進門的方式(連接方式)完全一樣~

?

🧹 第四步:自動執行數據庫遷移

連接好臨時數據庫后,pytest-django?還會自動做一件事:
運行所有?migrations(數據遷移文件),確保臨時數據庫的表結構和你的項目代碼完全同步。

就像:
臨時舞臺搭好了,但還得按設計圖(migrations?文件)擺好桌椅(數據表),演員(測試數據)才能上場~

?

🌟 總結:user?fixture 觸發的 “全自動流程”

  1. user?fixture 里的?User.objects.create_user()?觸發 “需要數據庫” 的信號
  2. pytest-django?接收到信號,創建臨時數據庫
  3. 自動修改數據庫配置,連接到臨時數據庫
  4. 自動運行遷移,確保表結構正確
  5. 執行?create_user,往臨時數據庫里寫入測試用戶數據

整個過程完全自動,不需要你手動寫?connect()?或?create_database()?之類的代碼~ 就像點外賣時,平臺自動幫你完成 “找餐廳、下單、配送”,你只需要等著吃(寫測試)就行啦! 😋

?

為什么resp = client.post(...) 就能把提交的data放到數據庫里呢

🌠 第一步:client.post(...)?是 “發件人”

🛣? 第二步:Django 路由 “指路”

🏭 第三步:視圖函數 “處理包裹”

register_view?視圖函數會打開包裹(data),做一系列操作:

  1. 檢查數據:比如看看用戶名是不是空的、密碼夠不夠長(就像快遞員檢查包裹是否違禁品)
  2. 創建用戶:如果數據沒問題,就會調用?User.objects.create_user(...)(Django 的 ORM 方法),把?data?里的用戶名、密碼等信息 “翻譯” 成數據庫能懂的語言(SQL 語句)。

📦 第四步:ORM 當 “翻譯官”,把數據存進數據庫

Django 的 ORM(對象關系映射)是個超厲害的 “翻譯官”:

  • 你寫的?User.objects.create_user(username="小明"),它會自動翻譯成 SQL 語句:
    INSERT INTO auth_user (username, password) VALUES ('小明', '加密后的密碼')
  • 然后通過之前?user?fixture 已經建好的數據庫連接,把這條 SQL 發給臨時數據庫執行。

數據庫收到指令后,就會在?auth_user?表(用戶表)里新增一行記錄 —— 你的?data?就這樣成功 “住進” 數據庫啦!

?

那沒有user這個固件了 直接resp = client.post(...) 能不能連接上數據庫

哈哈,這個問題就像在問:“如果沒有提前打開廚房門,能直接炒菜嗎?” 答案是 ——大部分情況會失敗!用超萌的例子解釋:

假設?user?fixture 是 “提前打開廚房門的人”👩🍳,而?client.post(...)?是 “炒菜的動作”:

?

🍳 情況 1:如果你的?post?請求需要操作數據庫(比如注冊用戶)

  • 這時候必須先有 “可用的廚房”(數據庫連接),否則炒不了菜~
  • 沒有?user?fixture,pytest-django?可能會 “偷懶” 不初始化數據庫(因為沒收到 “需要數據庫” 的信號)。
  • 當?client.post(...)?觸發視圖函數去寫數據庫時,會發現 “廚房門沒開”(數據庫沒連接),直接報錯:DatabaseError?或 “表不存在” 之類的錯誤~

就像沒開煤氣就想炒菜,鍋是冷的,根本炒不熟呀!

?

🍳 情況 2:如果你的?post?請求完全不碰數據庫(比如只是返回固定文本)

  • 比如視圖函數只是返回?{"code":0},不讀寫數據庫,那就算沒有?user?fixture,client.post(...)?也能正常運行~
  • 這就像 “涼拌菜”,不需要開火(數據庫),直接拌一拌就能吃~

?

📌 關鍵結論

client.post(...)?本身不會主動觸發數據庫連接,它只是發請求的 “快遞員”。
是否能連接數據庫,取決于測試中有沒有其他觸發數據庫初始化的操作(比如?user?fixture 里的?User.objects.create_user)。

如果你的?post?請求需要操作數據庫,最好還是帶上?user?fixture 或其他 “數據庫觸發器”(比如?django_db?fixture),確保 “廚房門是開著的” 哦~ 🔑

?

可是resp = client.post(...) 的后端視圖處理不是有創建User.objects.create_user的代碼嗎 為啥不能執行到這里的時候開始初始化數據庫

這個問題超棒!就像在問:“既然炒菜時會用到煤氣,為啥不能在炒菜時再開煤氣呢?” 這里藏著一個 “先后順序” 的小秘密~?

?

🔥 核心原因:“煤氣”(數據庫連接)必須在 “點火”(執行代碼)前打開

Django 測試中,數據庫初始化(連接、創建臨時表等)是 **“提前準備工作”,必須在任何數據庫操作代碼(比如?User.objects.create_user)執行之前 ** 完成。

而?client.post(...)?觸發的視圖函數里的?create_user,屬于 “測試過程中才會執行的代碼”—— 就像 “點火炒菜” 這個動作,必須在 “煤氣已經打開” 之后才能進行。

?

🍳 具體流程對比:

有?user?fixture 時:
  1. 測試開始前user?fixture 先執行?User.objects.create_user?→ 觸發數據庫初始化(開煤氣)
  2. 測試進行中client.post(...)?觸發視圖函數 → 執行?create_user(點火炒菜)→ 順利執行(煤氣已開)
沒有?user?fixture 時:
  1. 測試開始前:沒有任何數據庫操作 → pytest-django 認為 “不需要數據庫”→ 不初始化(沒開煤氣)
  2. 測試進行中client.post(...)?觸發視圖函數 → 執行?create_user(想點火炒菜)→ 發現 “煤氣沒開”(數據庫未初始化)→ 報錯!

?

🛠? pytest-django 的 “小規矩”:

pytest-django 有個 “懶加載” 原則:只有在測試開始前,檢測到 “明確需要數據庫” 的信號(比如 fixture 里有數據庫操作),才會提前初始化數據庫

而視圖函數里的?create_user?是 “測試運行到一半才執行的代碼”,這時候再想初始化數據庫已經太晚了 —— 就像炒菜炒到一半才發現沒開煤氣,火根本點不著呀!

?

🌟 解決辦法:給測試 “明確開煤氣”

如果不想用?user?fixture,也可以用 pytest-django 提供的?django_db?fixture,直接告訴 pytest:“我要用到數據庫,麻煩提前準備好哦~”

# 不用 user fixture,改用 django_db  fixture  
def test_register_post(client, django_db, data, code, msg):  resp = client.post("/accounts/register", data=data)  # 此時數據庫已提前初始化  # ... 后續斷言 ...  

django_db?就像一個 “備用煤氣開關”,專門負責在測試前打開數據庫連接~

可是不做單元測試 我只做開發的話視圖User.objects.create_user前也沒有什么啟動數據庫的操作啊

在實際開發中,情況和測試環境完全不同!就像 “家里做飯” 和 “野外露營做飯” 的區別 —— 家里的煤氣灶是長期打開、隨時可用的,而露營時需要提前手動生火~

?

🏠 開發環境中,數據庫連接是 “自動提前就緒” 的

在開發階段,當你啟動 Django 項目(比如?python manage.py runserver)時,Django 會自動完成一系列 “初始化工作”,其中就包括數據庫連接的建立,根本不需要你手動寫代碼 “啟動數據庫”。

具體來說,Django 會:

  1. 讀取?settings.py?里的數據庫配置(DATABASES?字典),比如數據庫類型(MySQL/PostgreSQL)、地址、用戶名密碼等。
  2. 啟動時自動創建數據庫連接池(保持和數據庫的 “長期通話” 狀態)。
  3. 檢查數據庫表結構(如果用了?migrate?遷移),確保表已經存在。

這就像你家里的煤氣灶,只要插上電、打開總開關,隨時擰旋鈕就能點火 ——數據庫連接在項目啟動時就已經 “待命” 了

?

🚀 所以視圖里的?User.objects.create_user?能直接執行

當用戶在瀏覽器里提交表單(或者你用 Postman 發請求),觸發視圖函數里的?User.objects.create_user?時:

  • Django 已經通過啟動時建立的數據庫連接,把 ORM 代碼(create_user)翻譯成 SQL。
  • 直接通過現成的連接發給數據庫執行,根本不需要 “臨時啟動數據庫”。

這和測試環境的區別在于:

  • 開發環境:項目啟動時強制初始化數據庫連接(因為?runserver?命令默認需要數據庫支持)。
  • 測試環境(pytest):為了效率,默認不初始化數據庫,只有明確告訴它 “要用數據庫”(比如用?django_db?fixture),才會提前準備。

?

📌 總結:開發時 “無需手動啟動” 的核心原因

Django 的?runserver?命令在啟動項目時,會自動根據?settings.py?的配置完成數據庫連接初始化,相當于 “項目一啟動,數據庫就處于‘開機待命’狀態”。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917476.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917476.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917476.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VUE-第二季-01

目錄 1.Vue程序初體驗 1.1 下載并安裝vue.js 1.2 第一個Vue程序 1.3 Vue的data配置項 1.4 Vue的template配置項 1.5 Vue實例 和 容器 的關系是&#xff1a;一夫一妻制 2.Vue核心技術 2.0 Vue的模板語法 2.0.1 插值語法 插值語法總結&#xff1a; 2.0.2 指令語法 指…

Android 15 中禁用/啟用應用的系統級方法

在 Android 15 的開發中,有時我們需要以系統級權限來控制應用的啟用狀態。本文將介紹如何使用 PackageManager 來實現應用的禁用和啟用功能。 核心方法 在 Android 15 代碼中,可以使用以下方法來禁用或啟用應用: packageManager.setApplicationEnabledSetting(pkg,Packag…

2025網絡工程師技能圖譜(附思維導圖)

------------比較全面&#xff0c;供學習參考路線圖。-----------------------

【ROS2】rclcpp::Node 常用 API

ROS 系列學習教程(總目錄) ROS2 系列學習教程(總目錄) 目錄1. 構造函數2. 節點名稱相關3. 獲取log對象句柄4. 回調組相關5. Topic發布與訂閱6. Service服務端與客戶端1. 構造函數 public:Node(const std::string & node_name, const NodeOptions & options NodeOptio…

自動駕駛:技術、應用與未來展望——從開創到全面革新交通出行

一、引言1.1 研究背景與意義在過去的幾十年里&#xff0c;隨著科技的飛速發展&#xff0c;自動駕駛技術逐漸從科幻小說中的概念走進了現實生活。從最初簡單的輔助駕駛功能&#xff0c;到如今高度自動化的自動駕駛系統&#xff0c;這一領域的進步正深刻地改變著我們的出行方式和…

【gradle】插件那些事

文章目錄 1. 前言 2. 插件相關介紹 2.1 gradle插件的apply 2.2 引入自定義插件 2.3 常見構建任務 2.4 gradle生命周期 2.5 gradle的惰性屬性&可注入的服務 2.6 常見命令 檢查依賴樹 查看tasks 構建掃描 查看多項目構建的結構 顯示所選項目的構建腳本依賴項 指定控制臺模式來…

測試平臺如何重塑CI/CD流程中的質量協作新范式

測試平臺如何重塑CI/CD流程中的質量協作新范式 在DevOps革命席卷全球軟件行業的今天&#xff0c;測試的角色正在經歷前所未有的轉變。傳統的"測試最后"模式正在被"測試全程"的新理念所取代&#xff0c;這一轉變背后是測試平臺與CI/CD流程深度融合帶來的質量…

node.js不同環境安裝配置

node.js不同環境安裝配置 Windows環境安裝配置 一、Node.js是什么&#xff1f; ? Node.js是一個基于Chrome V8引擎的[JavaScript運行環境]。 Node.js使用了一個事件驅動、非阻塞式I/O 的模型&#xff0c;Node.js是一個讓JavaScript運行在服務端的開發平臺&#xff0c;它讓J…

深度學習-讀寫模型網絡文件

模型網絡文件是深度學習模型的存儲形式&#xff0c;保存了模型的架構、參數等信息。讀寫模型網絡文件是深度學習流程中的關鍵環節&#xff0c;方便模型的訓練、測試、部署與共享。1. 主流框架讀寫方法&#xff08;一&#xff09;TensorFlow保存模型可以使用 tf.saved_model.sav…

智慧能源管理平臺的多層協同控制架構研究

摘要&#xff1a;針對微電網多源異構設備協同難題&#xff0c;提出一種“云-邊-端”三層智慧能源管理架構。平臺集成數據采集、策略優化與全景分析功能&#xff0c;支持光伏、儲能、充電樁等設備的動態調度&#xff0c;通過自適應算法實現防逆流、需量控制及峰谷套利等策略組合…

MySQL面試題及詳細答案 155道(021-040)

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

2025年IntelliJ IDEA最新下載、安裝教程,附詳細圖文

文章目錄下載與安裝IDEA大家好&#xff0c;今天為大家帶來的是IntelliJ IDEA的下載、安裝教程&#xff0c;親測可用&#xff0c;喜歡的朋友可以點贊收藏哦下載與安裝IDEA 首先先到官網下載最新版的IntelliJ IDEA, 下載后傻瓜式安裝就好了 1、下載完后在本地找到該文件&#xf…

深入解析 Apache Tomcat 配置文件

前言 Apache Tomcat 作為最流行的開源 Java Web 應用服務器之一&#xff0c;其強大功能的背后離不開一系列精心設計的配置文件。正確理解和配置這些文件&#xff0c;是部署、管理和優化 Web 應用的關鍵。本篇博客將深入探討 Tomcat 的核心配置文件&#xff0c;涵蓋其結構、關鍵…

ThinkPHP8學習篇(一):安裝與配置

ThinkPHP有非常多的功能庫&#xff0c;我的學習策略很明確&#xff1a;不貪多求全&#xff0c;只掌握最核心的20%功能&#xff0c;解決80%的業務需求。所有學習都圍繞一個目標&#xff1a;夠用就行。遇到復雜問題時&#xff0c;再具體學習對應的內容。 作為ThinkPHP學習的第一…

【Python練習】075. 編寫一個函數,實現簡單的語音識別功能

075. 編寫一個函數,實現簡單的語音識別功能 075. 編寫一個函數,實現簡單的語音識別功能 安裝依賴庫 示例代碼 代碼說明 示例輸出 注意事項 使用 PocketSphinx 進行離線語音識別 注意事項 實現方法 使用SpeechRecognition庫實現語音識別 使用PyAudio和深度學習模型 使用Vosk離…

chrome的數據采集插件chat4data的使用

簡介&#xff1a; Chat4Data是一款Chrome擴展插件&#xff0c;支持AI網頁數據采集與分析。用戶可通過Chrome應用商店安裝后&#xff0c;在網頁上選擇區塊和字段進行數據抓取&#xff0c;設置采集頁數后導出結果。該工具適用于結構化數據提取&#xff0c;操作簡便&#xff0c;為…

《人形機器人的覺醒:技術革命與碳基未來》——類人關節設計:人工肌肉研發進展及一款超生物肌肉Hypermusclet的設計與制造

目錄&#xff1a;一、人工股肉的不同種類及工作原理和比較優勢二、人工肌肉研發的重點難點及成果進展和趨勢三、人工肌肉主要研發機構及其研發成果四、人工肌肉主要性能檢測表征能力及標準體系建設五、人工肌肉主要制造商及其產品性能優勢和供應能力六、人工肌肉在機器人市場應…

【人工智能】AI代理的倫理迷局:自主智能體的責任歸屬之謎

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在人工智能時代,AI代理作為自主決策的代表,正深刻改變著人類社會。然而,其倫理困境日益凸顯:當AI代理做出自主決策時,誰應為其后果負責…

C語言數據結構(6)貪吃蛇項目1.貪吃蛇項目介紹

1. 游戲背景 貪吃蛇是久負盛名的游戲&#xff0c;它也和俄羅斯方塊&#xff0c;掃雷等游戲位列經典游戲的行列。 在編程語言的教學中&#xff0c;我們以貪吃蛇為例&#xff0c;從設計到代碼實現來提升學生的編程能力和邏輯能力。 2. 游戲效果演示 3. 項目目標 使用C語言…

神經網絡的并行計算與加速技術

神經網絡的并行計算與加速技術一、引言隨著人工智能技術的飛速發展&#xff0c;神經網絡在眾多領域展現出了巨大的潛力和廣泛的應用前景。然而&#xff0c;神經網絡模型的復雜度和規模也在不斷增加&#xff0c;這使得傳統的串行計算方式面臨著巨大的挑戰&#xff0c;如計算速度…