在測試並行開發(TPD)中,代碼開發是第一位的。儘管如此,我們還是要寫出開發的測試,並執行它們來驗證代碼的準確性(而不是直接運行代碼或使用控制台)。 在Python中,我們有一個叫做單元測試的過程,裡面有mock 和patch 函數。這篇文章將討論這兩個角色的用途和區別。 ### Mock 和Pat ...
在測試並行開發(TPD)中,代碼開發是第一位的。儘管如此,我們還是要寫出開發的測試,並執行它們來驗證代碼的準確性(而不是直接運行代碼或使用控制台)。
在Python中,我們有一個叫做單元測試的過程,裡面有mock 和patch 函數。這篇文章將討論這兩個角色的用途和區別。
Mock 和Patch 對象庫的用途和區別
在這篇文章中,我們不會把單元測試作為一個整體來處理,而是更多地關註於mock 和patch 函數。
我們使用mock Python包,用mock 對象替換你的被測系統的特定組件,並對它們的使用進行斷言。它是Python標準庫的一個組成部分,從Python 3.3開始可以作為unittest.mock 。
unittest.mock 類消除了在整個測試套件中對幾個存根的需要。在執行了一個特定的動作後,我們可以設置關於我們使用了哪些方法/屬性以及我們調用它們的參數的斷言。
它讓我們指定返回值並選擇需要的功能。
MagicDock可以處理Magic 對象,它是Mock 的子類。Mock 和MagicMock 對象在我們使用它們時自發地產生特性和方法,並記錄使用信息。
嘲諷是基於action -> assertion (即先讓mock 被使用,然後對它收到的調用進行斷言)模式,而不是許多嘲諷框架使用的record -> replay 模式。此外,mock 模塊提供了一個叫做patch() 的裝飾器,它負責在測試的上下文中修補類和模塊級別的特性,並提供了一個用於產生唯一實例的哨兵。
示例代碼:
from unittest.mock import patch
@patch('sample_module.sample_object')
def test_function(mock_object):
print(mock_object)
輸出:
<MagicMock name='sample_object' id='1870192341512'>
上面的代碼片段等同於下麵的代碼片段:
def test_function():
with patch('sample_module.sample_module') as mock_object:
print(mock_object)
該函數允許我們用mock 對象替換任何對象,以避免調用生產代碼,並檢查原始對象如何被調用(如果該對象是一個函數)。使用patch (或類似的方法)是首選,因為這可以確保補丁在測試後被還原(或在第二種情況下在上下文管理器範圍後被還原),這樣其他測試或程式就不會受到影響。
結論
我們可以註意到以下幾點來幫助我們的決策:
- 為了方便地用mock 對象(或其他對象)來替代對象,併在完成後恢復之前的狀態,或者在出現異常的情況下,使用patch 裝飾器/上下文管理器函數。
- mock.patch 創建mock 或衍生對象,我們可以手工製作。手動構建的只用於修複本地函數或其他不需要重置的模擬。