pytest-fixtured
fixture的作用
1.同unittest的setup和teardown,作為測試前后的初始化設置。
fixture的使用
1.作為前置條件使用
2.fixture的的作用范圍
1.作為前置條件使用
@pytest.fixture()
def a():
return 3
def test_b(a):
assert a==3
2.fixture的作用范圍
首先實例化更高范圍的fixture.默認為scope="function",每個測試函數都會執行一次。
- session : 多個.py文件執行時,只調用一次
- module: 每一個.py調用一次
- class : 每個類調用一次
- function: 每個函數調用一次
3.fixture 作為setup/teardown執行
yield 前的在測試之前執行,yield后的在測試完后執行
@pytest.fixture def a(): print("setup") yield print("teardown") def test_b(a): print("測試")
4.fixture with
# @pytest.fixture() # def write_file(): # f = open("myfile.txt","w") # f.write("hello") # yield # f.close() @pytest.fixture() def write_file(): with open("myfile.txt","w") as f: f.write("hello1") def test_write_file(write_file): print("ceshi")
5. fixture request可以請求測試的上下文
@pytest.fixture(params=[1,3]) def a(request): return request.param def test_b(a): assert a in [1,3]
6.fixture 工廠模式
在單個測試中,如果想多次調用該fixture,就可以用工廠模式。fixture的結果返回的不是數據,而是返回生成數據的函數。
@pytest.fixture def make_customer_record(): def _make_customer_record(name): return {"name": name, "orders": []} return _make_customer_record def test_customer_records(make_customer_record): customer_1 = make_customer_record("Lisa") customer_2 = make_customer_record("Mike") customer_3 = make_customer_record("Meredith")
7.帶參數的fixture
params列表有幾個值,測試就會執行幾次。例params=[1,2],測試用例會執行2次
@pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)]) def data_set(request): return request.param def test_data(data_set): assert data_set in [0,1]
8. 模塊化:在一個fixtrue調用另一個fixture
fixture a可以調用另一個fixture c
@pytest.fixture() def c(): print("c") @pytest.fixture() def a(c): print("a") def test_b(a): pass
9.通過fixture 對測試用例進行分組
pytest在測試運行期間最大程度地減少了fixture的數量。如果有參數化的fixtrue,那么使用它的所有測試將首先使用一個實例執行,然后在創建下一個fixture實例之前調用終結器。除其他外,這簡化了對創建和使用全局狀態的應用程序的測試。
@pytest.fixture(scope="module", params=[1, 2])
def input_x(request):
print("setup")
param = request.param
yield param
print("teardown")
def test_a(input_x): print("test_a") assert input_x in [1,2] def test_b(input_x): print("test_b") assert input_x in [1,2] if __name__ == '__main__': pytest.main(['-q','fixture_1.py']) 運行結果 fixture_1.py setup .test_a .test_b teardown setup .test_a .test_b teardown
如上所示,設置scope='module',會將所有調用該fixture的用例都執行一遍,而fixture只執行了一次。
10.使用類、模塊、項目中的fixture
userfixtures,可以調用在其他模塊定義好的fixture.
@pytest.mark.usefixtures("x") class TestCase: def test_1(self): print("test_1") def test_2(self): print("test_2") if __name__ == '__main__': pytest.main(['-q','test_2.py'])
a.usefixture,可以添加多個fixture
@pytest.mark.usefixtures("a", "b") def test(): pass
b.可以使用標記機制的通用功能在測試模塊級別指定fixture
pytestmark = pytest.mark.usefixtures("a") def test_a(): def test_b():
c.可以將項目中所有測試所需的fixture放入ini文件中
#pytest.ini [pytest] usefixtures = x #test_case.py @pytest.mark.usefixtures def test_a(): pass
11.自動使用fixture
autouse=True
有時你可能希望自動調用fixture, 而無需顯示聲明函數參數或usefixtures裝飾器。
import pytest class DB: def __init__(self): self.intransaction = [] def begin(self, name): self.intransaction.append(name) def rollback(self): self.intransaction.pop() @pytest.fixture(scope="module") def db(): return DB() class TestClass: @pytest.fixture(autouse=True) def transact(self, request, db): db.begin(request.function.__name__) yield db.rollback() def test_method1(self, db): assert db.intransaction == ["test_method1"] def test_method2(self, db): assert db.intransaction == ["test_method2"]
類級transact夾具標記有autouse = true ,這意味著該類中的所有測試方法都將使用此夾具,而無需在測試函數簽名或類級usefixtures修飾器中聲明它。
- autouse固定裝置遵循
scope=關鍵字參數:如果有autouse固定裝置,scope='session'則無論定義在何處,都只能運行一次。scope='class'表示它將每節課運行一次,依此類推。 - 如果在測試模塊中定義了自動使用夾具,則其所有測試功能都會自動使用它。
- 如果在conftest.py文件中定義了自動使用的固定裝置,則其目錄下所有測試模塊中的所有測試都將調用固定裝置。
- 最后,請謹慎使用:如果您在插件中定義了自動使用夾具,它將在安裝該插件的所有項目中的所有測試中調用它。如果固定裝置僅在某些設置下(例如在ini文件中)仍然可以工作,則這很有用。這樣的全局夾具應始終快速確定它是否應該做任何工作,并避免其他昂貴的導入或計算。
請注意,上面的transact燈具很可能是您希望在項目中不啟用的燈具。做到這一點的規范方法是將事務處理定義放入conftest.py文件中,而無需使用autouse:
# content of conftest.py @pytest.fixture def transact(request, db): db.begin() yield db.rollback()
然后例如通過聲明需要讓TestClass使用它:
@pytest.mark.usefixtures("transact") class TestClass: def test_method1(self): ...
該TestClass中的所有測試方法都將使用事務處理夾具,而模塊中的其他測試類或功能將不使用它,除非它們也添加了transact引用。
fixture覆蓋
1.對于測試文件夾級別,具有相同名稱的fixture可以被覆蓋
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def username():
return 'username'
test_something.py
# content of tests/test_something.py
def test_username(username):
assert username == 'username'
subfolder/
__init__.py
conftest.py
# content of tests/subfolder/conftest.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-' + username
test_something.py
# content of tests/subfolder/test_something.py
def test_username(username):
assert username == 'overridden-username'
2.在測試模塊中覆蓋fixture
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def username():
return 'username'
test_something.py
# content of tests/test_something.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-' + username
def test_username(username):
assert username == 'overridden-username'
test_something_else.py
# content of tests/test_something_else.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-else-' + username
def test_username(username):
assert username == 'overridden-else-username'
3.在文件內覆蓋
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def username():
return 'username'
@pytest.fixture
def other_username(username):
return 'other-' + username
test_something.py
# content of tests/test_something.py
import pytest
@pytest.mark.parametrize('username', ['directly-overridden-username'])
def test_username(username):
assert username == 'directly-overridden-username'
@pytest.mark.parametrize('username', ['directly-overridden-username-other'])
def test_username_other(other_username):
assert other_username == 'other-directly-overridden-username-other'
4.對于某些測試模塊,參數化的夾具被非參數化的版本覆蓋,而非參數化的夾具被參數化的版本覆蓋。顯然,測試文件夾級別也是如此。
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture(params=['one', 'two', 'three'])
def parametrized_username(request):
return request.param
@pytest.fixture
def non_parametrized_username(request):
return 'username'
test_something.py
# content of tests/test_something.py
import pytest
@pytest.fixture
def parametrized_username():
return 'overridden-username'
@pytest.fixture(params=['one', 'two', 'three'])
def non_parametrized_username(request):
return request.param
def test_username(parametrized_username):
assert parametrized_username == 'overridden-username'
def test_parametrized_username(non_parametrized_username):
assert non_parametrized_username in ['one', 'two', 'three']
test_something_else.py
# content of tests/test_something_else.py
def test_username(parametrized_username):
assert parametrized_username in ['one', 'two', 'three']
def test_username(non_parametrized_username):
assert non_parametrized_username == 'username'
實用技巧
1.conftest.py 共享fixture。如果定義fixture過多且需要多個地方調用,可將fixture放入conftest.py文件中,使用時不需要導入

浙公網安備 33010602011771號