mock.patch 是 python 單元測試中用于臨時替換對象的工具。它屬于 unittest.mock 模塊,可作為裝飾器或上下文管理器使用,能在測試期間將指定對象替換成 mock 實例,并在測試結束后自動恢復原狀。常見用法包括:1. 替換函數返回值,例如模擬 requests.get() 的響應;2. 使用裝飾器或 with 語句控制 patch 的作用范圍;3. 區別 patch 類方法與實例方法;4. 注意路徑準確性、作用域及副作用處理,如使用 side_effect 模擬異常或動態返回結果。
在寫python單元測試的時候,mock.patch 是一個非常實用的工具。它能讓我們在測試過程中臨時替換掉某些對象,比如函數、類或者模塊,這樣我們就能控制它們的行為,而不依賴真實環境。
什么是 mock.patch?
mock.patch() 是 Python unittest.mock 模塊中的一個裝飾器或上下文管理器,用于在測試期間“打補丁”某個對象。也就是說,它可以在運行時替換成你指定的對象,比如一個 Mock 實例,等測試結束后自動恢復原樣。
常見用法包括:
- 替換某個模塊中的函數
- 模擬某個類的返回值
- 控制外部依賴(如網絡請求、數據庫讀取)
怎么用 mock.patch?
替換函數返回值
這是最常見的使用方式之一。比如你想測試某個調用了 requests.get() 的函數,但不想讓它真正發起網絡請求。
立即學習“Python免費學習筆記(深入)”;
from unittest.mock import patch import requests def fetch_data(): response = requests.get('https://example.com') return response.status_code @patch('requests.get') def test_fetch_data(mock_get): mock_get.return_value.status_code = 200 assert fetch_data() == 200
這里的關鍵是:你要 patch 的名字必須是你被測試代碼中實際導入和使用的那個名字,而不是原始定義的位置。
使用裝飾器還是上下文管理器?
- 裝飾器適用于整個測試函數都要替換的情況。
- with 語句適合只在某一段代碼里替換。
# 裝飾器寫法 @patch('module.ClassName') def test_something(mock_class): ... # 上下文寫法 def test_something(): with patch('module.ClassName') as mock_class: ...
兩種方式效果一樣,選哪個看具體場景。
patch 類和實例方法的區別
有時候你會想模擬某個類的方法行為,這時候需要注意 patch 的目標不同:
- patch 類方法:直接 patch 類上的方法
- patch 實例方法:需要先構造實例,再 patch 實例上的方法
例如:
class MyClass: def method(self): return 'real' # Patch 整個類的方法 @patch.object(MyClass, 'method', return_value='mocked') def test_class_method(mock_method): obj = MyClass() assert obj.method() == 'mocked'
常見問題與注意事項
- 路徑要寫對:patch 的路徑一定要準確,通常是模塊+對象名,比如 ‘my_module.requests.get’
- 作用域別搞混:如果你在 A 模塊里導入了 B 模塊的函數,那要 patch 的是 A 模塊里看到的那個引用
- 注意副作用:如果被 mock 的函數有多個調用點,return_value 可能不夠用,可以用 side_effect 來模擬異常或動態返回
side_effect 示例:
mock_get.side_effect = Exception('Network error')
基本上就這些。mock.patch 不復雜,但在實際項目中很容易因為路徑寫錯或理解偏差導致 mock 失敗,所以多注意細節。