Pytest 裝置

已完成

裝置是 pytest 協助程式函式,用來建立模組化、可調整且可維護的測試。 您可以使用裝置來設定測試的先決條件,例如資料庫連線、建立測試數據,或設定測試執行前所需的系統狀態。 測試完成執行之後,它們也可以用於清除。

pytest 裝置的主要特性包括:

  • 範圍控制:裝置可以使用 參數來設定不同的範圍 scope (例如 functionclassmodulesession),以決定呼叫裝置的頻率。
  • 設定和卸除的處理:P ytest 會管理裝置的生命週期,並視需要自動設定和卸除。
  • 相依性插入:裝置會插入測試函式作為自變數,明確指出哪些測試依賴哪些裝置。
  • 重複使用性和模組化:裝置可以在一個位置定義,並跨多個測試函式、模組或甚至專案使用。

建立暫存盤裝置

撰寫與檔案互動的測試時,通常需要不會雜亂文件系統後續測試的暫存盤。 透過 pytest,我們可以建立設定暫存盤的裝置。 裝置會使用 Python 的 tempfile 模組安全地產生暫存盤,確保可以使用和刪除它們,而不會影響本機環境。 (在此初始版本的裝置中,檔案不會因為 delete=False 旗標而自動刪除。我們稍後會處理刪除檔案的問題。)

以下是裝置的外觀:

import pytest
import tempfile

@pytest.fixture
def tmp_file():
    def create():
        # Create a named temporary file that persists beyond the function scope
        temp = tempfile.NamedTemporaryFile(delete=False)
        return temp.name
    return create

在此設定中, tmp_file() 做為裝置。 裝置的名稱是測試參考它的方式。 在裝置內,巢狀函 create() 式只會在呼叫 時建立檔案,而不是在裝置設定時建立檔案。 這可讓您精確控制建立暫存盤的時間,這在時機和檔案狀態很重要的測試中很有用。

在巢狀函式 create()中,會建立暫存盤,然後傳回其絕對路徑。 以下是測試如何使用我們撰寫的裝置的範例:

import os

def test_file(tmp_file):
    path = tmp_file()
    assert os.path.exists(path)

測試會藉由指定裝置的名稱做為自變數,來使用裝置。 透過寫入檔案或進行修改,例如變更許可權或擁有權,即可輕鬆地擴充我們的簡單使用案例。

範圍管理

在 pytest 中,透過設定和卸除例程管理測試資源的生命週期對於維護乾淨且有效率的測試環境至關重要。 您也想要確保每個測試都以已知且一致的狀態開始,以保護測試的完整性。 根據預設,pytest 裝置會以 function 兩種方式影響行為的範圍運作:

  • 每個測試的生命週期:裝置的傳回值會針對使用該測試的每個測試函式重新計算,確保每個測試都以全新狀態運作。
  • 每次使用後清除:在利用裝置的每個測試之後,都會執行任何必要的清除作業。

Pytest 也可讓裝置範圍更廣,以優化效能和資源使用量。 在管理資料庫狀態,或當您有複雜狀態設定時,建立耗時的情況,範圍特別有用。 可用的四個範圍如下:

  • function:預設範圍,每個測試會執行一次裝置
  • class:每個測試類別都會執行一次裝置。
  • module:針對模組執行一次。
  • session:每個測試會話執行一次。 此範圍適用於需要在整個測試會話中保存的昂貴作業,例如初始化服務或啟動資料庫伺服器。

在此情況下, 執行一次 表示會快取傳回值。 因此,具有「模組」範圍的裝置可以在測試模組中呼叫數次,但傳回值是第一個呼叫它的測試。

tmp_file()以下是裝置與模組範圍的外觀:

import pytest
import tempfile

@pytest.fixture(scope="module")
def tmp_file():
    def create():
        temp = tempfile.NamedTemporaryFile(delete=False)
        return temp.name
    return create

清除管理

指定裝置的 tmp_file 先前程式代碼會建立暫存盤,但在測試完成後,它不會自動處理清除。 為了確保暫存盤不會留下,您可以使用 pytest 的 request 裝置來註冊清除函式。

以下是您可以修改 tmp_file 裝置以包含自動清除的方式:

import pytest
import tempfile
import os

@pytest.fixture(scope="module")
def tmp_file(request):
    # Create a temporary file that persists beyond the function scope
    temp = tempfile.NamedTemporaryFile(delete=False)

    def create():
        # Returns the path of the temporary file
        return temp.name

    def cleanup():
        # Remove the file after the tests are done
        os.remove(temp.name)

    # Register the cleanup function to be called after the last test in the module
    request.addfinalizer(cleanup)

    return create

藉由使用 request.addfinalizer() 並傳遞巢狀 cleanup() 函式,清除會根據範圍來呼叫。 在此案例中,範圍為 module,因此在模組 pytest 呼叫清除函式的所有測試之後。

使用 conftest.py

您可以將其儲存在 conftest.py 檔案中,而不是在測試檔案中包含您的裝置。 conftest.py 中的所有裝置都會自動提供給相同目錄中的測試,而不需要明確匯入它們。

探索內建裝置

Pytest 有許多專為簡化測試而設計的內建裝置。 這些裝置可以自動處理設定和清除,讓您專注於撰寫測試案例,而不是測試管理。

主要內建裝置包括:

  • cache:用來建立和管理測試層級快取,這對於在測試會話之間儲存數據很有用。
  • capsys:擷取並允許檢查 stderrstdout,讓您輕鬆檢查及測試控制台輸出。
  • tmpdir:提供測試期間需要建立及使用之檔案的暫存目錄。
  • monkeypatch:提供一種方式,安全地修改物件、函式和作系統環境的行為和值。

猴子修補在測試中的角色

測試與資料庫或外部 API 等外部資源緊密整合的程式代碼,可能會因為相關的相依性而具有挑戰性。 稱為 「猴子修補 」的技術涉及在測試回合期間暫時修改您的系統,這可讓您獨立於外部系統,並可讓您在測試期間安全地改變作系統環境的狀態和行為。

以下是如何使用裝置覆寫函 os.path.exists() 式的 monkeypatch 範例:

import os

def test_os(monkeypatch):
    # Override os.path.exists to always return False
    monkeypatch.setattr('os.path.exists', lambda x: False)
    assert not os.path.exists('/')

或者,您可以使用 setattr() 方法搭配對象和屬性的直接參考:

def test_os(monkeypatch):
    # Specify the object and attribute to override
    monkeypatch.setattr(os.path, 'exists', lambda x: False)
    assert not os.path.exists('/')

除了設定屬性和覆寫方法之外, monkeypatch 裝置還可以設定和刪除環境變數、變更字典值,以及修改系統路徑。 裝置 monkeypatch 會在每次測試之後自動還原任何變更,但在使用 monkeypatch 裝置時仍應小心。 以下是使用時要小心的一些原因:

- 程序代碼清楚和維護:過度使用 monkeypatch 或以複雜方式使用它,可讓測試更加難以理解和維護。 當您閱讀測試結果時,可能不會立即清楚元件應該如何正常運作,以及它們如何修改以進行測試。 - 測試有效性:猴子修補有時會導致在與生產環境非常不同的人為條件下通過的測試。 這可能會造成錯誤的安全性感,因為測試可能會因為測試改變系統的行為而大幅改變。 - 過度依賴實作詳細數據:依賴猴子修補的測試可能會緊密結合他們正在測試之程式代碼的特定實作詳細數據。 這會使測試變得脆弱且容易中斷,甚至對基礎程式代碼基底進行次要變更。 - 偵錯複雜度:偵錯使用 monkeypatch 的測試可能更為複雜,特別是當修補程式變更應用程序行為的基本層面時。 瞭解測試失敗的原因,可能需要更深入地探討測試期間如何修改元件。

雖然 monkeypatch 是建立隔離和控制測試環境的強大工具,但應該謹慎使用,並清楚瞭解它如何影響測試套件和應用程式的行為。