pytest 支持開箱即用地運行基于 Python 單元測試的測試。 它旨在利用現(xiàn)有的基于單元測試的測試套件將 pytest 用作測試運行器,并允許逐步調(diào)整測試套件以充分利用 pytest 的功能。
要使用 pytest 運行現(xiàn)有的 ?unittest
樣式的測試套件,請鍵入:
pytest tests
pytest 將自動在 ?test_*.py
? 或 ?*_test.py
? 文件中收集 ?unittest.TestCase
? 子類及其測試方法。
幾乎所有單元測試功能都受支持:
@unittest.skip style decorators
?setUp/tearDown
?setUpClass/tearDownClass
?setUpModule/tearDownModule
?到目前為止,pytest 不支持以下功能:
load_tests protocol
?subtests
?通過使用 pytest 運行您的測試套件,您可以利用多個功能,在大多數(shù)情況下無需修改現(xiàn)有代碼:
-k
? 和 ?-m
? 標志測試選擇選項N
? 次)失敗后停止-pdb
? 用于調(diào)試測試失敗的命令行選項pytest-xdist
? 插件將測試分發(fā)到多個 CPUself.assert*
? 函數(shù)(?unittest2pytest
在這方面非常有幫助)以下 pytest 功能在 ?unittest.TestCase
子類中工作:
Marks
?: ?skip
?, ?skipif
?, ?xfail
?Auto-use fixtures
?以下 pytest 功能不起作用,并且由于設(shè)計理念不同,可能永遠不會起作用:
Fixtures
?Parametrization
??Custom ?hooks
?第三方插件可能運行良好,也可能運行不佳,具體取決于插件和測試套件。
在pytest中運行unittest允許你在unittest中使用它的?fixture
?機制。TestCase風格測試。假設(shè)你已經(jīng)瀏覽了pytest ?fixture
?的特性,讓我們開始一個集成了?pytest db_class fixture
?的例子,設(shè)置一個類緩存的數(shù)據(jù)庫對象,然后從一個unittest風格的測試引用它:
# content of conftest.py
# we define a fixture function below and it will be "used" by
# referencing its name from tests
import pytest
@pytest.fixture(scope="class")
def db_class(request):
class DummyDB:
pass
# set a class attribute on the invoking test context
request.cls.db = DummyDB()
這定義了一個?fixture
?函數(shù)?db_class
?,如果使用,則對每個測試類調(diào)用一次,并將類級別的?db
?屬性設(shè)置為一個?DummyDB
?實例。?fixture
?函數(shù)通過接收一個特殊的請求對象來實現(xiàn)這一點,該請求對象提供對請求測試上下文的訪問,比如cls屬性,它表示使用?fixture
?的類。這種體系結(jié)構(gòu)將?fixture
?的編寫與實際的測試代碼分離開來,并允許通過最小引用(?fixture
?名稱)重用?fixture
?。我們來寫一個?unittest
?。?TestCase
?類使用我們的?fixture
?定義:
# content of test_unittest_db.py
import unittest
import pytest
@pytest.mark.usefixtures("db_class")
class MyTest(unittest.TestCase):
def test_method1(self):
assert hasattr(self, "db")
assert 0, self.db # fail for demo purposes
def test_method2(self):
assert 0, self.db # fail for demo purposes
?@pytest.mark.usefixtures("db_class")
類裝飾器確保每個類調(diào)用一次 pytest ?fixture
?函數(shù) ?db_class
?,由于故意失敗的斷言語句,我們可以查看回溯中的self.db
值:
$ pytest test_unittest_db.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items
test_unittest_db.py FF [100%]
================================= FAILURES =================================
___________________________ MyTest.test_method1 ____________________________
self = <test_unittest_db.MyTest testMethod=test_method1>
def test_method1(self):
assert hasattr(self, "db")
> assert 0, self.db # fail for demo purposes
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef0001>
E assert 0
test_unittest_db.py:10: AssertionError
___________________________ MyTest.test_method2 ____________________________
self = <test_unittest_db.MyTest testMethod=test_method2>
def test_method2(self):
> assert 0, self.db # fail for demo purposes
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef0001>
E assert 0
test_unittest_db.py:13: AssertionError
========================= short test summary info ==========================
FAILED test_unittest_db.py::MyTest::test_method1 - AssertionError: <conft...
FAILED test_unittest_db.py::MyTest::test_method2 - AssertionError: <conft...
============================ 2 failed in 0.12s =============================
這個默認的 pytest 回溯顯示這兩個測試方法共享同一個 ?self.db
? 實例,這是我們在上面編寫類范圍的?fixture
函數(shù)時的意圖。
雖然對于給定的測試,顯式聲明所需使用的?fixture
?通常更好,但有時您可能希望在給定的上下文中自動使用?fixture
?。畢竟,?unittest-setup
?的傳統(tǒng)風格要求使用這種隱式的?fixture
?編寫,您可能已經(jīng)習慣或喜歡它了。
您可以使用?@pytest.fixture(autuse =True)
?標記?fixture
?函數(shù),并在希望使用它的上下文中定義?fixture
?函數(shù)。讓我們看一下?initdir fixture
?,它使?TestCase
?類的所有測試方法在一個帶有預先初始化的?samplefile.ini
?的臨時目錄中執(zhí)行。我們的?initdir fixture
?本身使用pytest內(nèi)置的?tmp_path fixture
?來委托創(chuàng)建每個測試的臨時目錄:
# content of test_unittest_cleandir.py
import os
import pytest
import unittest
class MyTest(unittest.TestCase):
@pytest.fixture(autouse=True)
def initdir(self, tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path) # change to pytest-provided temporary directory
tmp_path.joinpath("samplefile.ini").write_text("# testdata")
def test_method(self):
with open("samplefile.ini") as f:
s = f.read()
assert "testdata" in s
由于有?autuse
?標志,?initdir fixture
?函數(shù)將用于定義它的類的所有方法。這是在類上使用?@pytest.mark.usefixture ("initdir")
?標記的快捷方式,就像前面的例子一樣。
運行這個測試模塊:
$ pytest -q test_unittest_cleandir.py
. [100%]
1 passed in 0.12s
上述測試通過,因為?initdir fixture
?函數(shù)在?test_method
?之前被執(zhí)行。
?unittest.TestCase
? 方法不能直接接收?fixture
?參數(shù)作為實現(xiàn),這可能會影響運行通用 ?unittest.TestCase
? 測試套件的能力。
上面的 ?usefixtures
?和 ?autouse
?示例應該有助于將 pytest ?fixture
?混合到單元測試套件中。
您還可以逐漸從 ?unittest.TestCase
? 的子類化轉(zhuǎn)移到普通斷言,然后開始逐步受益于完整的 pytest 功能集。
由于兩個框架之間的架構(gòu)差異,基于單元測試的設(shè)置和拆卸是在測試的調(diào)用階段執(zhí)行的,而不是在pytest的標準設(shè)置和拆卸階段。在某些情況下,理解這一點很重要,特別是在推理錯誤時。例如,如果基于單元測試的套件在安裝期間出現(xiàn)錯誤,pytest在安裝階段報告沒有錯誤,而是在調(diào)用期間引發(fā)錯誤。
更多建議: