棄用和移除

此頁面列出了目前已棄用或在過去主要版本中已移除的所有 pytest 功能。目的是讓使用者清楚了解特定功能被移除的原因,以及應該改用哪些替代方案。

已棄用的功能

以下是所有被認為已棄用的 pytest 功能的完整列表。使用這些功能將會發出 PytestWarning 或子類別,可以使用 標準警告過濾器 進行過濾。

pytest.importorskip 關於 ImportError 的預設行為

自版本 8.2 起已棄用。

傳統上,pytest.importorskip() 會捕獲 ImportError,最初的目的是在未安裝相依模組時跳過測試,例如使用不同相依性進行測試。

然而,有些套件可能已安裝在系統中,但由於其他問題(例如編譯錯誤或安裝損壞)而無法導入。在這些情況下,pytest.importorskip() 仍然會靜默地跳過測試,但通常使用者更希望看到意外錯誤,以便可以修復根本問題。

8.2 版本中,新增了 exc_type 參數,讓使用者能夠傳遞 ModuleNotFoundError,以便僅在模組確實找不到時才跳過測試,而不是因為其他錯誤。

預設情況下僅捕獲 ModuleNotFoundError(並讓其他錯誤傳播)將是最佳解決方案,但為了向後兼容性,pytest 將保留現有行為,但在以下情況發出警告:

  1. 捕獲的異常類型為 ImportError,且

  2. 使用者未明確傳遞 exc_type

如果導入嘗試引發 ModuleNotFoundError(通常情況),則模組將被跳過,且不會發出警告。

這樣一來,常見情況將保持相同的工作方式,而意外錯誤現在將發出警告,使用者可以通過明確傳遞 exc_type=ImportError 來抑制警告。

9.0 版本中,警告將轉變為錯誤,而在 9.1 版本中,pytest.importorskip() 預設情況下將僅捕獲 ModuleNotFoundError,並且不再發出警告 – 但使用者仍然可以通過將 ImportError 傳遞給 exc_type 來捕獲它。

Node 建構函式的 fspath 參數已替換為 pathlib.Path

自版本 7.0 起已棄用。

為了支持從 py.path.localpathlib 的過渡,Node 建構函式(例如 pytest.Function.from_parent()pytest.Class.from_parent())的 fspath 參數現在已被棄用。

建構節點的插件應傳遞類型為 pathlib.Pathpath 參數,而不是 fspath 參數。

實作自訂項目和收集器的插件,建議將 fspath 參數 (py.path.local) 替換為 path 參數 (pathlib.Path),並盡可能放棄任何其他 py 庫的使用。

如果可能,具有自訂項目的插件應使用協作建構函式,以避免硬編碼它們僅傳遞給超類的參數。

注意

Node 參數和屬性的名稱(新屬性為 path)與 hook 的情況相反,如下所述(舊參數為 path)。

這是由於歷史原因造成的不幸產物,應在未來版本中解決,因為我們正在慢慢擺脫對 py 的依賴(有關更長的討論,請參閱 #9283)。

由於正在進行諸如 reportinfo() 等方法的遷移,這些方法仍預期返回 py.path.local 對象,因此節點仍然同時具有 fspath (py.path.local) 和 path (pathlib.Path) 屬性,無論在建構函式中使用哪個參數。我們預計在未來版本中棄用 fspath 屬性。

使用標記配置 hook 規範/實作

在 pluggy(pytest 的插件庫)成為獨立套件並具有清晰的 API 之前,pytest 僅使用 pytest.mark 來配置 hook。

pytest.hookimpl()pytest.hookspec() 裝飾器已存在多年,應改為使用它們。

@pytest.mark.tryfirst
def pytest_runtest_call(): ...


# or
def pytest_runtest_call(): ...


pytest_runtest_call.tryfirst = True

應更改為

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_call(): ...

已更改的 hookimpl 屬性

  • tryfirst

  • trylast

  • optionalhook

  • hookwrapper

已更改的 hookwrapper 屬性

  • firstresult

  • historic

hook 的 py.path.local 參數已替換為 pathlib.Path

自版本 7.0 起已棄用。

為了支持從 py.path.localpathlib 的過渡,以下 hook 現在接收額外參數

隨附的基於 py.path.local 的路徑已被棄用:手動調用這些 hook 的插件應僅傳遞新的 pathlib.Path 參數,使用者應更改其 hook 實作以使用新的 pathlib.Path 參數。

注意

Node 參數和屬性的名稱,如上所述(新屬性為 path)與 hook 的情況相反(舊參數為 path)。

這是由於歷史原因造成的不幸產物,應在未來版本中解決,因為我們正在慢慢擺脫對 py 的依賴(有關更長的討論,請參閱 #9283)。

直接建構內部類別

自版本 7.0 起已棄用。

直接建構以下類別現在已被棄用

  • _pytest.mark.structures.Mark

  • _pytest.mark.structures.MarkDecorator

  • _pytest.mark.structures.MarkGenerator

  • _pytest.python.Metafunc

  • _pytest.runner.CallInfo

  • _pytest._code.ExceptionInfo

  • _pytest.config.argparsing.Parser

  • _pytest.config.argparsing.OptionGroup

  • _pytest.pytester.HookRecorder

這些建構函式一直被認為是私有的,但現在發出棄用警告,這可能會在 pytest 8 中變成硬錯誤。

pytest.Collectorpytest.Item 之間的菱形繼承

自版本 7.0 起已棄用。

定義一個同時為 ItemCollector 的自訂 pytest 節點類型(例如 File)現在會發出警告。它從未得到合理的支援,並且會觸發難以調試的錯誤。

一些提供 linting/程式碼分析的插件一直將此作為一種 hack 使用。相反,應使用單獨的收集器節點,以收集項目。有關範例,請參閱使用非 Python 測試,以及修復繼承的範例 pr

自訂 Node 子類的建構函式應接受 **kwargs

自版本 7.0 起已棄用。

如果諸如 pytest.Item 之類的節點的自訂子類別覆寫 __init__ 方法,則它們應接受 **kwargs。因此,

class CustomItem(pytest.Item):
    def __init__(self, name, parent, additional_arg):
        super().__init__(name, parent)
        self.additional_arg = additional_arg

應改為

class CustomItem(pytest.Item):
    def __init__(self, *, additional_arg, **kwargs):
        super().__init__(**kwargs)
        self.additional_arg = additional_arg

以避免硬編碼 pytest 可以傳遞給超類的參數。有關完整範例,請參閱使用非 Python 測試

對於沒有衝突的情況,不會發出棄用警告。對於有衝突的情況(例如,pytest.File 現在採用 path 而不是 fspath,如上所述),現在會發出棄用警告。

將標記應用於 fixture 函數

自版本 7.4 起已棄用。

將標記應用於 fixture 函數從來沒有任何效果,但這是一個常見的使用者錯誤。

@pytest.mark.usefixtures("clean_database")
@pytest.fixture
def user() -> User: ...

使用者在此情況下預期 usefixtures 標記會產生預期的效果,即在調用 user 時使用 clean_database fixture,但實際上它根本沒有任何效果。

現在,pytest 在遇到此問題時會發出警告,並將在未來版本中引發錯誤。

在測試函數中返回非 None 值

自版本 7.2 起已棄用。

如果測試函數返回除 None 以外的任何值,則現在會發出 pytest.PytestReturnNotNoneWarning

這可以防止初學者之間的一個常見錯誤,他們期望返回 bool 會導致測試通過或失敗,例如

@pytest.mark.parametrize(
    ["a", "b", "result"],
    [
        [1, 2, 5],
        [2, 3, 8],
        [5, 3, 18],
    ],
)
def test_foo(a, b, result):
    return foo(a, b) == result

鑑於 pytest 忽略了返回值,這可能會令人驚訝,因為它永遠不會失敗。

正確的修復方法是將 return 更改為 assert

@pytest.mark.parametrize(
    ["a", "b", "result"],
    [
        [1, 2, 5],
        [2, 3, 8],
        [5, 3, 18],
    ],
)
def test_foo(a, b, result):
    assert foo(a, b) == result

yield_fixture 函數/裝飾器

自版本 6.2 起已棄用。

pytest.yield_fixturepytest.fixture() 的已棄用別名。

它已經這樣很長時間了,因此可以安全地搜索/替換。

已移除的功能和重大變更

正如我們的向後兼容性政策政策中所述,已棄用的功能僅在經過適當的棄用期後的主要版本中移除。

也列出了一些無法棄用的重大變更。

支援為 nose 編寫的測試

自版本 7.2 起已棄用。

在版本 8.0 中移除。

現在已棄用對運行為 nose 編寫的測試的支援。

nose 多年來一直處於僅維護模式,並且維護插件並非易事,因為它會蔓延到程式碼庫中(有關更多詳細信息,請參閱 #9886)。

setup/teardown

一件可能讓使用者感到驚訝的事情是,普通的 setupteardown 方法不是 pytest 原生的,它們實際上是 nose 支援的一部分。

class Test:
    def setup(self):
        self.resource = make_resource()

    def teardown(self):
        self.resource.close()

    def test_foo(self): ...

    def test_bar(self): ...

原生 pytest 支援使用 setup_methodteardown_method(請參閱方法和函數級別的 setup/teardown),因此上述應更改為

class Test:
    def setup_method(self):
        self.resource = make_resource()

    def teardown_method(self):
        self.resource.close()

    def test_foo(self): ...

    def test_bar(self): ...

這在整個程式碼庫中很容易做到,只需進行簡單的查找/替換即可。

@with_setup

使用 @with_setup 的程式碼,例如這樣

from nose.tools import with_setup


def setup_some_resource(): ...


def teardown_some_resource(): ...


@with_setup(setup_some_resource, teardown_some_resource)
def test_foo(): ...

也需要移植到受支援的 pytest 風格。一種方法是使用 fixture

import pytest


def setup_some_resource(): ...


def teardown_some_resource(): ...


@pytest.fixture
def some_resource():
    setup_some_resource()
    yield
    teardown_some_resource()


def test_foo(some_resource): ...

compat_co_firstlineno 屬性

Nose 檢查函數對象上的此屬性,以允許覆寫函數的推斷行號。Pytest 不再遵守此屬性。

msg= 傳遞給 pytest.skippytest.failpytest.exit

自版本 7.0 起已棄用。

在版本 8.0 中移除。

現在已棄用將關鍵字參數 msg 傳遞給 pytest.skip()pytest.fail()pytest.exit(),應改為使用 reason。此變更是為了使這些函數與已經接受 reason 參數的 @pytest.mark.skip@pytest.mark.xfail 標記保持一致。

def test_fail_example():
    # old
    pytest.fail(msg="foo")
    # new
    pytest.fail(reason="bar")


def test_skip_example():
    # old
    pytest.skip(msg="foo")
    # new
    pytest.skip(reason="bar")


def test_exit_example():
    # old
    pytest.exit(msg="foo")
    # new
    pytest.exit(reason="bar")

pytest.Instance 收集器

在版本 7.0 中移除。

pytest.Instance 收集器類型已移除。

以前,Python 測試方法被收集為 Class -> Instance -> Function。現在,Class 直接收集測試方法。

大多數引用 Instance 的插件這樣做是為了忽略或跳過它,使用諸如 if isinstance(node, Instance): return 之類的檢查。此類插件應僅在 pytest>=7 上移除對 Instance 的考慮。但是,為了保持此類用途的正常運作,已在 pytest.Instance_pytest.python.Instance 中實例化一個虛擬類型,並且導入它會發出棄用警告。這在 pytest 8 中已移除。

使用 pytest.warns(None)

自版本 7.0 起已棄用。

在版本 8.0 中移除。

pytest.warns(None) 現在已被棄用,因為它經常被誤用。其正確用法是檢查程式碼是否發出至少一個任何類型的警告 - 例如 pytest.warns()pytest.warns(Warning)

有關範例,請參閱測試中警告的其他用例

Parser.addoption 中的向後兼容性

自版本 2.4 起已棄用。

在版本 8.0 中移除。

Parser.addoption 的幾個行為現在已在 pytest 8 中移除(自 pytest 2.4.0 起已棄用)

  • parser.addoption(..., help=".. %default ..") - 請改用 %(default)s

  • parser.addoption(..., type="int/string/float/complex") - 請改用 type=int 等。

--strict 命令列選項

自版本 6.2 起已棄用。

在版本 8.0 中移除。

--strict 命令列選項已被棄用,而改用 --strict-markers,後者能更好地傳達該選項的作用。

我們計劃在未來可能會重新引入 --strict,並使其成為所有與嚴格性相關的選項(目前為 --strict-markers--strict-config,未來可能會引入更多)的包容性標誌。

實作 pytest_cmdline_preparse hook

自版本 7.0 起已棄用。

在版本 8.0 中移除。

實作 pytest_cmdline_preparse hook 已被正式棄用。請改為實作 pytest_load_initial_conftests hook。

def pytest_cmdline_preparse(config: Config, args: List[str]) -> None: ...


# becomes:


def pytest_load_initial_conftests(
    early_config: Config, parser: Parser, args: List[str]
) -> None: ...

pytest 8 中的收集變更

新增了一個新的 pytest.Directory 基礎收集節點,預期所有文件系統目錄的收集器節點都將繼承自它。這類似於現有的文件節點 pytest.File

pytest.Package 更改為 pytest.Directory 的子類別。Package 代表一個文件系統目錄,它是一個 Python 套件,即包含一個 __init__.py 文件。

pytest.Package 現在僅收集其自身目錄中的文件;以前它是遞迴收集的。子目錄作為子收集器節點收集,從而創建一個反映文件系統層次結構的收集樹。

session.name 現在為 "";以前它是 rootdir 目錄名稱。這與 session.nodeid 一致,後者始終為 ""

新增了一個新的 pytest.Dir 具體收集節點,它是 pytest.Directory 的子類別。此節點代表一個文件系統目錄,它不是 pytest.Package,即不包含 __init__.py 文件。與 Package 類似,它僅收集其自身目錄中的文件,同時將子目錄作為子收集器節點收集。

現在,文件和目錄以字母順序聯合收集,除非被插件更改。以前,文件在目錄之前收集。

現在,收集樹包含直到 rootdir 的目錄/套件,對於在 rootdir 中找到的初始參數。對於 rootdir 之外的文件,僅收集直接目錄/套件 – 但請注意,不鼓勵從 rootdir 外部收集。

例如,給定以下文件系統樹

myroot/
    pytest.ini
    top/
    ├── aaa
    │   └── test_aaa.py
    ├── test_a.py
    ├── test_b
    │   ├── __init__.py
    │   └── test_b.py
    ├── test_c.py
    └── zzz
        ├── __init__.py
        └── test_zzz.py

收集樹,如 pytest --collect-only top/ 所示,但為了清楚起見,添加了原本隱藏的 Session 節點,現在如下所示

<Session>
  <Dir myroot>
    <Dir top>
      <Dir aaa>
        <Module test_aaa.py>
          <Function test_it>
      <Module test_a.py>
        <Function test_it>
      <Package test_b>
        <Module test_b.py>
          <Function test_it>
      <Module test_c.py>
        <Function test_it>
      <Package zzz>
        <Module test_zzz.py>
          <Function test_it>

以前是

<Session>
  <Module top/test_a.py>
    <Function test_it>
  <Module top/test_c.py>
    <Function test_it>
  <Module top/aaa/test_aaa.py>
    <Function test_it>
  <Package test_b>
    <Module test_b.py>
      <Function test_it>
  <Package zzz>
    <Module test_zzz.py>
      <Function test_it>

程式碼/外掛程式若依賴特定集合樹狀結構,可能需要更新。

pytest.Package 不再是 pytest.Modulepytest.File

版本 8.0 已變更。

Package 收集器節點指定一個 Python 套件,也就是含有 __init__.py 檔案的目錄。 過去,Packagepytest.Module (代表單一 Python 模組) 的子類型,而模組是 __init__.py 檔案。 這已被視為設計上的錯誤 (詳情請參閱 #11137#7777)。

Package 節點的 path 屬性現在指向套件目錄,而不是 __init__.py 檔案。

請注意,__init__.pyModule 節點 (它不是 Package) 仍然可能存在,如果在收集期間被選取 (例如,如果您設定 python_files 以包含 __init__.py 檔案)。

收集 __init__.py 檔案不再收集套件

在版本 8.0 中移除。

執行 pytest pkg/__init__.py 現在僅收集 pkg/__init__.py 檔案 (模組)。 以前,它會收集整個 pkg 套件,包含目錄中的其他測試檔案,但不包含 __init__.py 檔案本身中的測試 (除非 python_files 已變更為允許 __init__.py 檔案)。

若要收集整個套件,請僅指定目錄:pytest pkg

pytest.collect 模組

自版本 6.0 起已棄用。

在版本 7.0 中移除。

pytest.collect 模組不再是公共 API 的一部分,其所有名稱現在都應直接從 pytest 匯入。

pytest_warning_captured hook

自版本 6.0 起已棄用。

在版本 7.0 中移除。

此 hook 有一個 item 參數,無法由 pytest-xdist 序列化。

請改用 pytest_warning_recorded hook,它以 nodeid 參數取代 item 參數。

pytest._fillfuncargs 函數

自版本 6.0 起已棄用。

在版本 7.0 中移除。

保留此函數是為了與舊版外掛程式向後相容。

其功能不應直接使用,但如果您必須取代它,請改用 function._request._fillfixtures(),但請注意這不是公共 API,未來可能會中斷。

--no-print-logs 命令列選項

自版本 5.4 起已棄用。

已在版本 6.0 中移除。

已移除 --no-print-logs 選項和 log_print ini 設定。 如果您使用過它們,請改用 --show-capture

pytest 3.5.0 中新增了 --show-capture 命令列選項,可讓您指定在測試失敗時如何顯示擷取的輸出:nostdoutstderrlogall (預設值)。

結果記錄 (--result-log)

自版本 4.0 起已棄用。

已在版本 6.0 中移除。

--result-log 選項會產生測試報告串流,可在執行階段分析,但它使用自訂格式,需要使用者實作自己的剖析器。

pytest-reportlog 外掛程式提供 --report-log 選項,這是一個更標準且可擴充的替代方案,每行產生一個 JSON 物件,並且應涵蓋相同的使用案例。 請試用看看並提供意見回饋。

pytest-reportlog 外掛程式甚至可能會在某個時間點合併到核心中,具體取決於外掛程式的計畫以及使用者的數量。

pytest_collect_directory hook

已在版本 6.0 中移除。

pytest_collect_directory hook 多年來一直無法正常運作 (它被呼叫但結果被忽略)。 使用者可以考慮改用 pytest_collection_modifyitems

TerminalReporter.writer

已在版本 6.0 中移除。

TerminalReporter.writer 屬性已被棄用,不應再使用。 這在無意中作為該外掛程式公共 API 的一部分公開,並將其與 py.io.TerminalWriter 綁定得太緊密。

直接使用 TerminalReporter.writer 的外掛程式應改用提供相同功能的 TerminalReporter 方法。

junit_family 預設值變更為 “xunit2”

版本 6.0 已變更。

junit_family 選項的預設值將在 pytest 6.0 中變更為 xunit2,這是舊版 xunit1 格式的更新,並且在現代工具中預設支援,這些工具會操作此類型的檔案 (例如,Jenkins、Azure Pipelines 等)。

建議使用者試用新的 xunit2 格式,並查看其取用 JUnit XML 檔案的工具是否支援它。

若要使用新格式,請更新您的 pytest.ini

[pytest]
junit_family=xunit2

如果您發現您的工具不支援新格式,並且想要繼續使用舊版,請將選項設定為 legacy

[pytest]
junit_family=legacy

透過使用 legacy,當升級到 pytest 6.0 時,您將繼續使用舊版/xunit1 格式,其中預設格式將為 xunit2

為了讓使用者了解過渡期,如果命令列中給定了 --junit-xml 選項,但 junit_family 未在 pytest.ini 中明確設定,pytest 將發出警告。

已知支援 xunit2 格式的服務

節點建構變更為 Node.from_parent

版本 6.0 已變更。

現在節點的建構應使用具名建構函式 from_parent。 API 介面中的此限制旨在實現更好/更簡單的集合樹狀結構重構。

這表示現在必須調用 MyItem.from_parent(collector, name="foo"),而不是 MyItem(name="foo", parent=collector, obj=42)

希望支援舊版 pytest 並抑制警告的外掛程式可以使用 hasattr 來檢查該版本中是否存在 from_parent

def pytest_pycollect_makeitem(collector, name, obj):
    if hasattr(MyItem, "from_parent"):
        item = MyItem.from_parent(collector, name="foo")
        item.obj = 42
        return item
    else:
        return MyItem(name="foo", parent=collector, obj=42)

請注意,from_parent 應僅使用參數的關鍵字引數呼叫。

pytest.fixture 引數僅限關鍵字

已在版本 6.0 中移除。

已移除將引數作為位置引數傳遞給 pytest.fixture() 的功能 - 請改用關鍵字傳遞。

funcargnames 別名為 fixturenames

已在版本 6.0 中移除。

FixtureRequestMetafuncFunction 類別會追蹤其相關聯 fixture 的名稱,並使用適當命名的 fixturenames 屬性。

在 pytest 2.3 之前,此屬性名為 funcargnames,自那時起我們一直將其保留為別名。 它最終即將移除,因為在我們或外掛程式作者必須區分 fixture 名稱和非 fixture 物件 (例如 pytest.mark.parametrize) 提供的名稱時,它通常會造成混淆。

pytest.config 全域變數

已在版本 5.0 中移除。

已棄用 pytest.config 全域物件。 請改用 request.config (透過 request fixture);如果您是外掛程式作者,請使用 pytest_configure(config) hook。 請注意,許多 hook 也可以間接存取 config 物件,例如透過 session.configitem.config

pytest.raises"message" 參數

已在版本 5.0 中移除。

常見的錯誤是認為此參數會比對例外訊息,但實際上它僅用於在 pytest.raises 檢查失敗時提供自訂訊息。 為了防止使用者犯此錯誤,並且因為認為它很少使用,pytest 正在棄用它,目前沒有提供替代方案。

如果您有此參數的有效使用案例,請考慮為了獲得相同的結果,您只需在 with 陳述式結尾手動呼叫 pytest.fail 即可。

例如

with pytest.raises(TimeoutError, message="Client got unexpected message"):
    wait_for(websocket.recv(), 0.5)

變成

with pytest.raises(TimeoutError):
    wait_for(websocket.recv(), 0.5)
    pytest.fail("Client got unexpected message")

如果您仍然對此棄用和未來移除有疑慮,請在 #3974 上發表評論。

以字串作為第二個引數的 raises / warns

已在版本 5.0 中移除。

請改用這些的上下文管理器形式。 必要時,直接調用 exec

範例

pytest.raises(ZeroDivisionError, "1 / 0")
pytest.raises(SyntaxError, "a $ b")

pytest.warns(DeprecationWarning, "my_function()")
pytest.warns(SyntaxWarning, "assert(1, 2)")

變成

with pytest.raises(ZeroDivisionError):
    1 / 0
with pytest.raises(SyntaxError):
    exec("a $ b")  # exec is required for invalid syntax

with pytest.warns(DeprecationWarning):
    my_function()
with pytest.warns(SyntaxWarning):
    exec("assert(1, 2)")  # exec is used to avoid a top-level warning

在自訂收集器中使用 Class

已在版本 4.0 中移除。

已棄用使用名為 "Class" 的物件作為自訂在 Collector 子類別中收集的節點類型的方式。 使用者應改用 pytest_pycollect_makeitem 在收集期間自訂節點類型。

此問題應僅影響建立新集合類型的高階外掛程式,因此如果您看到此警告訊息,請聯絡作者,以便他們可以變更程式碼。

pytest.mark.parametrize 中的標記

已在版本 4.0 中移除。

現在已棄用將標記套用至 pytest.mark.parametrize 呼叫的值。 例如

@pytest.mark.parametrize(
    "a, b",
    [
        (3, 9),
        pytest.mark.xfail(reason="flaky")(6, 36),
        (10, 100),
        (20, 200),
        (40, 400),
        (50, 500),
    ],
)
def test_foo(a, b): ...

此程式碼將 pytest.mark.xfail(reason="flaky") 標記套用至上述參數化呼叫的 (6, 36) 值。

這被認為難以閱讀和理解,而且其實作也為程式碼帶來了問題,阻礙了標記架構的進一步內部改進。

若要更新程式碼,請使用 pytest.param

@pytest.mark.parametrize(
    "a, b",
    [
        (3, 9),
        pytest.param(6, 36, marks=pytest.mark.xfail(reason="flaky")),
        (10, 100),
        (20, 200),
        (40, 400),
        (50, 500),
    ],
)
def test_foo(a, b): ...

pytest_funcarg__ 字首

已在版本 4.0 中移除。

在非常早期的 pytest 版本中,可以使用 pytest_funcarg__ 字首定義 fixture

def pytest_funcarg__data():
    return SomeData()

切換到 @pytest.fixture 裝飾器

@pytest.fixture
def data():
    return SomeData()

setup.cfg 檔案中的 [pytest] 區段

已在版本 4.0 中移除。

現在應將 setup.cfg 檔案中的 [pytest] 區段命名為 [tool:pytest],以避免與其他 distutils 命令衝突。

Metafunc.addcall

已在版本 4.0 中移除。

Metafunc.addcall 是目前參數化機制的先驅。 使用者應改用 pytest.Metafunc.parametrize()

範例

def pytest_generate_tests(metafunc):
    metafunc.addcall({"i": 1}, id="1")
    metafunc.addcall({"i": 2}, id="2")

變成

def pytest_generate_tests(metafunc):
    metafunc.parametrize("i", [1, 2], ids=["1", "2"])

cached_setup

已在版本 4.0 中移除。

request.cached_setup 是 fixture 可用的 setup/teardown 機制的先驅。

範例

@pytest.fixture
def db_session():
    return request.cached_setup(
        setup=Session.create, teardown=lambda session: session.close(), scope="module"
    )

應更新此機制以使用標準 fixture 機制

@pytest.fixture(scope="module")
def db_session():
    session = Session.create()
    yield session
    session.close()

您可以查閱 文件中的 funcarg 比較章節 以取得更多資訊。

非最上層 conftest 檔案中的 pytest_plugins

已在版本 4.0 中移除。

在非最上層 conftest.py 檔案中定義 pytest_plugins 現在已被棄用,因為它們會全域啟用參考的外掛程式,這令人感到意外,因為對於所有其他 pytest 功能,conftest.py 檔案僅在位於或低於它的測試中有效

Config.warnNode.warn

已在版本 4.0 中移除。

這些方法是內部 pytest 警告系統的一部分,但自 3.8 起,pytest 針對其自身的警告使用內建警告系統,因此這兩個函數現在已被棄用。

Config.warn 應替換為對標準 warnings.warn 的呼叫,例如

config.warn("C1", "some warning")

變成

warnings.warn(pytest.PytestWarning("some warning"))

Node.warn 現在支援兩種簽名

  • node.warn(PytestWarning("some message")):現在是呼叫此函數的建議方式。 警告實例必須是 PytestWarning 或子類別。

  • node.warn("CI", "some message"):此程式碼/訊息形式已被移除,應轉換為上述警告實例形式。

record_xml_property

已在版本 4.0 中移除。

現在已棄用 record_xml_property fixture,改用更通用的 record_property,後者可供其他消費者 (例如 pytest-html) 用於取得有關測試執行的自訂資訊。

這只是重新命名 fixture 的問題,因為 API 是相同的

def test_foo(record_xml_property): ...

變更為

def test_foo(record_property): ...

將命令列字串傳遞至 pytest.main()

已在版本 4.0 中移除。

已棄用將命令列字串傳遞至 pytest.main()

pytest.main("-v -s")

請改為傳遞清單

pytest.main(["-v", "-s"])

透過傳遞字串,使用者期望 pytest 將使用他們正在使用的 shell 規則 (例如 bashPowershell) 解釋該命令列,但這很難/不可能以可移植的方式完成。

直接呼叫 fixture

已在版本 4.0 中移除。

已棄用直接呼叫 fixture 函數,而不是在測試函數中請求它們。

例如

@pytest.fixture
def cell():
    return ...


@pytest.fixture
def full_cell():
    cell = cell()
    cell.make_full()
    return cell

這對新使用者來說是一個很大的困惑來源,他們經常會交替呼叫 fixture 函數並從測試函數中請求它們,這會破壞 fixture 解析模型。

在這些情況下,只需在相依 fixture 中直接請求函數即可

@pytest.fixture
def cell():
    return ...


@pytest.fixture
def full_cell(cell):
    cell.make_full()
    return cell

或者,如果 fixture 函數在測試中被多次呼叫 (使其難以套用上述模式),或者如果您想要對程式碼進行最小的變更,您可以建立一個 fixture,該 fixture 使用 name 參數呼叫原始函數。

def cell():
    return ...


@pytest.fixture(name="cell")
def cell_fixture():
    return cell()

yield 測試

已在版本 4.0 中移除。

pytest 支援 yield 樣式的測試,其中測試函數實際上 yield 函數和值,然後將其轉換為適當的測試方法。 範例

def check(x, y):
    assert x**x == y


def test_squared():
    yield check, 2, 4
    yield check, 3, 9

這將產生兩個實際產生的測試函數。

此形式的測試函數不正確地支援 fixture,使用者應切換到 pytest.mark.parametrize

@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared(x, y):
    assert x**x == y

透過 Node 存取的內部類別

已在版本 4.0 中移除。

透過 Node 實例存取 ModuleFunctionClassInstanceFileItem 現在會發出此警告

usage of Function.Module is deprecated, please use pytest.Module instead

使用者應僅 import pytest 並使用 pytest 模組存取這些物件。

這已記錄為棄用多年,但直到現在我們才實際發出棄用警告。

Node.get_marker

已在版本 4.0 中移除。

作為大型標記改版和迭代的一部分,已移除 _pytest.nodes.Node.get_marker。 請參閱關於如何更新程式碼的提示的文件

somefunction.markname

已在版本 4.0 中移除。

作為大型標記改版和迭代的一部分,我們已棄用使用 MarkInfo,取得元素標記的唯一正確方法是透過 node.iter_markers(name)

pytest_namespace

已在版本 4.0 中移除。

此 hook 已被棄用,因為它極大地複雜化了關於配置和初始化的 pytest 內部結構,使得某些錯誤修復和重構變得不可能。

使用範例

class MySymbol: ...


def pytest_namespace():
    return {"my_symbol": MySymbol()}

依賴此 hook 的外掛程式作者應改為要求使用者現在直接匯入外掛程式模組 (使用適當的公共 API)。

作為權宜之計,外掛程式作者仍然可以將其名稱注入 pytest 的命名空間中,通常在 pytest_configure 期間進行

import pytest


def pytest_configure():
    pytest.my_symbol = MySymbol()