pytest自動化測試中的fixture的聲明和調(diào)用
1. fixture的聲明
我們使用@pytest.fixture()來聲明fixture函數(shù)。fixture()即可無參數(shù)進(jìn)行聲明,也可以帶參數(shù)聲明。
示例1:
@pytest.fixture()無參數(shù)進(jìn)行聲明
import pytest
@pytest.fixture#fixture()未帶任何參數(shù),聲明一個fixture函數(shù)
def fixture_demo():
print("這個是一個fixture的demo演示")
def test_demo(fixture_demo): #調(diào)用fixture函數(shù)——fixture_demo
print("這是一個測試demo。")
@pytest.fixture()有參數(shù)的進(jìn)行聲明
通過上文pytest中fixtureAPI簡單說明,我們對fixture()的參數(shù)有了一定了解。fixture()可以帶著這些參數(shù)去聲明一個fixture函數(shù)。
import pytest
@pytest.fixture(params=[1,2,3]) #fixture()帶著parmas對ids()進(jìn)行fixture函數(shù)的聲明
def ids(request):
data=request.param
print(f'獲取測試數(shù)據(jù){data}')
return data
def test_ids(ids): #調(diào)用fixture函數(shù)-ids()
print(ids)
2. fixture的調(diào)用
2.1 fixture的調(diào)用方式
fixture有三種調(diào)用方式,分別為:
1. 使用 fixturename
2. 使用@pytest.mark.usefixtures(“fixturename”)
3. autouse——自動應(yīng)用
2.1.1 使用fixturename
通過pytest中fixtureAPI簡單說明中對@fixture()參數(shù)的介紹,我們知道fixturename默認(rèn)是@pytest.fixture()所裝飾的函數(shù)的函數(shù)名,如果傳入name參數(shù),則fixturename就是name傳入的內(nèi)容。
當(dāng)要調(diào)用fixture的時候,只要將fixturename作為參數(shù)傳入測試函數(shù)即可。
示例2:
1.使用被裝飾的函數(shù)的函數(shù)名
import pytest
@pytest.fixture() #未傳入name,因此fixturename為函數(shù)名login
def login():
print('login')
def test_case1(login): #將fixturename作為參數(shù)傳入
print('這是testcase1')
2.使用fixture別名
import pytest
@pytest.fixture(name='login1') #傳入name,因此fixturename為login1
def login():
print('login')
def test_case1(login1): #將fixturename作為參數(shù)傳入
print('這是testcase1')
注意:
當(dāng)使用fixture的別名后,被裝束函數(shù)的函數(shù)名失效,無法再繼續(xù)使用其進(jìn)行fixture的調(diào)用。

2.1.2 使用@pytest.mark.usefixtures("fixturename")
根據(jù)pytest官方文檔的介紹,如果想讓某個fixture適用于類、模塊和項目中所有測試函數(shù)的話,會使用usefixtures來調(diào)用fixture。當(dāng)然,單個測試函數(shù)也可以使用此方法來調(diào)用fixture。
使用usefixtures調(diào)用fixture和直接使用fixturename來調(diào)用fixture是有區(qū)別的,可總結(jié)為:
使用usefixtures調(diào)用的fixture只能用于配置測試前系統(tǒng)的初始狀態(tài),無法為測試用例提供測試數(shù)據(jù);但使用fixturename調(diào)用的fixture卻可以實現(xiàn)這兩個功能。
示例:
1.聲明一個名為login的fixture,并通過fixture()傳入測試數(shù)據(jù)集。test_case1使用usefixtures的方法調(diào)用login,并且在函數(shù)內(nèi)部想要打印login的返回值。
import pytest
@pytest.fixture(params=[1,2,3]) # 傳入測試數(shù)據(jù)集
def login(request):
print("登陸操作")
return request.param #返回測試數(shù)據(jù)
class TestClass1:
@pytest.mark.usefixtures('login') #使用usefixtures調(diào)用login
def test_case1(self):
print("這是Testclass1中testcase1")
print(login) #打印login
運行后發(fā)現(xiàn),結(jié)果和我們預(yù)期的不一樣,print(login)打印出的是函數(shù)對象信息,不是返回值。

2.修改剛剛的代碼,使用fixturename來調(diào)用login
import pytest
@pytest.fixture(params=[1,2,3]) # 傳入測試數(shù)據(jù)集
def login(request):
print("登陸操作")
return request.param #返回測試數(shù)據(jù)
class TestClass1:
#@pytest.mark.usefixtures('login') #使用usefixtures調(diào)用login
def test_case1(self,login): #使用fixturename的方式調(diào)用login
print("這是Testclass1中testcase1")
print(login) #打印login
運行后我們可以發(fā)現(xiàn),結(jié)果和我們預(yù)期的一致,把login的返回值成功打印出來。

usefixtures調(diào)用fixture的方法只適用于測試函數(shù),對于fixture函數(shù)不生效;使用fixturename調(diào)用fixture的方法對測試函數(shù)和fixture函數(shù)都適用。
示例:
1.以下demo想要實現(xiàn)執(zhí)行測試用例前打印“登陸操作”,用例執(zhí)行結(jié)束后打印“注銷操作”。聲明login和logout為fixture函數(shù),并且讓logout使用usefixtures的方法調(diào)用login,再讓test_case1調(diào)用logout。
import pytest
@pytest.fixture()
def login():
print("登陸操作")
@pytest.mark.usefixtures('login') @pytest.fixture() def logout():
yield
print("注銷操作")
class TestClass1:
def test_case1(self,logout):
print("這是Testclass1中testcase1")
通過運行結(jié)果我們發(fā)現(xiàn),結(jié)果只在執(zhí)行測試函用例后打印了“注銷操作”,與我們預(yù)期的結(jié)果不一致。

2.修改上面的demo代碼,讓logout使用fixturename的方式調(diào)用login。
import pytest
@pytest.fixture()
def login():
print("登陸操作")
#@pytest.mark.usefixtures('login')
@pytest.fixture()
def logout(login): #使用fixturename的方式調(diào)用login
yield
print("注銷操作")
class TestClass1:
def test_case1(self,logout):
print("這是Testclass1中testcase1")
運行后我們發(fā)現(xiàn),結(jié)果與我們預(yù)期的一致。

由此可以看出來,userfixtures的調(diào)用方法對于fixture函數(shù)無效。
下面我們將通過示例來演示userfixtures的使用方法:
為了演示效果,我們新建一個包,并在里面創(chuàng)建一個conftest.py。用于定義fixture函數(shù)。關(guān)于conftest.py的相關(guān)內(nèi)容,后面會單獨寫一遍文章詳細(xì)介紹。

在conftest.py中聲明的一個login函數(shù)。
import pytest
@pytest.fixture()
def login():
print('登錄操作')
1.整個類中應(yīng)用fixture
使用usefixtures,讓TestClass1這個類中所有測試函數(shù)都調(diào)用login。
import pytest
@pytest.mark.usefixtures('login') #讓TestClass1調(diào)用login
class TestClass1:
def test_case1(self):
print("這是Testclass1中testcase1")
def test_case2(self):
print('這是Testclass1中testcase2')
class TestClass2:
def test_case3(self):
print('這是Testclass2中的testcase3')
運行結(jié)果:
通過結(jié)果我們可以發(fā)現(xiàn),只有TestClass1中的test_case1和test_case2調(diào)用了login。

2.整個模塊應(yīng)用fixture
根據(jù)官方文檔說明,在整個模塊中應(yīng)用fixture,可在模塊使用
pytestmark=pytest.mark.usefixtures("fixturename")。
修改測試代碼如下:
import pytest
pytestmark = pytest.mark.usefixtures("login") #使用pytestmark在模塊中使用usefixtures
class TestClass1:
def test_case1(self):
print("這是Testclass1中testcase1")
def test_case2(self):
print('這是Testclass1中testcase2')
class TestClass2:
def test_case3(self):
print('這是Testclass2中的testcase3')
運行結(jié)果:
通過運行結(jié)果可發(fā)現(xiàn),整個模塊中,所有測試類里面的測試函數(shù)都調(diào)用了login。

3.整個項目中使用
在pytest.ini中配置usefixtures。
演示項目結(jié)構(gòu)如圖:

對應(yīng)文件中的代碼如下:
test_demo中的test_demo.py:
class TestClass1:
def test_case1(self):
print("這是pytest_demo包中test_demo模塊里Testclass1中testcase1")
class TestClass2:
def test_case2(self):
print('這是pytest_demo包中test_demo模塊里Testclass2中的testcase2')
test_usefixtures中的test_usefixtures.py:
class TestClass1:
def test_case1(self):
print("這是pytest_usefixtures包中test_usefixtures模塊里Testclass1中testcase1")
class TestClass2:
def test_case2(self):
print('這是pytest_usefixtures包中test_usefixtures模塊里Testclass2中的testcase2')
TestDemo根目錄下的conftest.py:
import pytest
@pytest.fixture()
def login():
print('登錄操作')
TestDemo根目錄下的pytest.ini:
[pytest] usefixtures = login
運行整個項目:
項目中的測試函數(shù)都調(diào)用了conftest.py中的login。

4.使用usefixtures調(diào)用多個fixture
我們可以使用@pytest.mark.usefixtures('fixturename1','fixturename2')來調(diào)用多個fixture。
conftest.py中新增一個fixture:
import pytest
@pytest.fixture()
def login():
print('登錄操作')
@pytest.fixture()
def printids():
print("打印ids。")
修改test_usefixtures.py:
@pytest.mark.usefixtures('login','printids')
class TestClass1:
def test_case1(self):
print("這是pytest_usefixtures包中test_usefixtures模塊里Testclass1中testcase1")
運行后結(jié)果:
test_case1測試函數(shù)調(diào)用login和printids兩個fixture。

2.1.3 autouse——自動應(yīng)用
fixture()的autouse參數(shù),是fixture自動應(yīng)用的標(biāo)識。
如果autouse=True,則在同作用域下的測試函數(shù),會自動調(diào)用該fixture;如果autouse=False,則測試函數(shù)需要主動去調(diào)用該fixture。
autouse默認(rèn)是False。
示例4:
1.在TestClass1這個類中定義了一個login函數(shù),聲明為fixture,并且autouse設(shè)置為True。
TestClass1中的test_case1主動調(diào)用了login,但是其他測試函數(shù)未主動調(diào)用。
我們還寫了一個TestClass2類,類中有一個test_case4的測試函數(shù)。
import pytest
class TestClass1:
@pytest.fixture(autouse=True) # 啟用自動應(yīng)用
def login(self):
print("登陸操作")
def test_case1(self,login): # 調(diào)用了login這個fixture函數(shù)
print("這是Testclass1中testcase1")
def test_case2(self): # 沒有調(diào)用
print('這是Testclass1中testcase2')
def test_case3(self): # 沒有調(diào)用
print('這是Testclass1中testcase3')
class TestClass2:
def test_case4(self):
print('這是Testclass2中的testcase4')
運行結(jié)果:
通過運行結(jié)果我們可以知道,當(dāng)fixture的autouse=True的時候,在同作用域內(nèi)的測試函數(shù)會自動調(diào)用fixture,非同作用域內(nèi)的測試函數(shù)無法調(diào)用。

2.我們給fixture()帶上更多的參數(shù),修改上面的demo,并設(shè)置fixture的scope=‘class'。
import pytest
@pytest.fixture(scope='class', autouse=True) # fixture的作用域設(shè)為class級別,啟用自動應(yīng)用
def login():
print("登陸操作")
class TestClass1:
def test_case1(self):
print("這是Testclass1中testcase1")
def test_case2(self):
print('這是Testclass1中testcase2')
def test_case3(self):
print('這是Testclass1中testcase3')
class TestClass2:
def test_case4(self):
print('這是Testclass2中的testcase4')
運行結(jié)果:
通過運行結(jié)果我們可以看出,當(dāng)設(shè)置login的scope=‘class'的使用,每一個測試類都會自動調(diào)用一次login。
autouse的使用也是遵照fixture函數(shù)的設(shè)置來進(jìn)行的。

2.2 fixture使用的靈活性
通過官方文檔的說明,我們知道了pytest的fixture系統(tǒng)是極其的靈活和強(qiáng)大的,官方文檔也為我們以下幾個靈活使用fixture的例子。
2.2.1 一個fixture函數(shù)可以調(diào)用其他的fixture
文章前面我們有演示過一個fixture函數(shù)調(diào)用其他fixture的例子。
代碼如下:
import pytest
@pytest.fixture()
def login():
print("登陸操作")
@pytest.fixture()
def logout(login):
yield
print("注銷操作")
class TestClass1:
def test_case1(self,logout):
print("這是Testclass1中testcase1")
login()實現(xiàn)了測試執(zhí)行的前置操作,logout()實現(xiàn)了測試執(zhí)行的后置操作。logout()調(diào)用了login,測試函數(shù)則直接調(diào)用了logout。
fixture在執(zhí)行的時候是依次執(zhí)行的。假如fixture A 調(diào)用了fixture B,那么執(zhí)行的時候會先執(zhí)行fixture B,然后再執(zhí)行fixture A。因為fixture B是fixture A的依賴條件。
所以我們運行上面代碼的時候,是會先調(diào)用login()然后再調(diào)用logout()的。而logout()中的yield會讓測試用例執(zhí)行的時候先執(zhí)行login中的測試前置操作,然后再執(zhí)行測試用例中的內(nèi)容,最后執(zhí)行logout中yield后面測試后置操作。
這樣的一個操作,可以將復(fù)雜的測試需求,變成一個一個簡單而又有組織性的的功能函數(shù),更加方便后期進(jìn)行維護(hù)。
2.2.2 fixture函數(shù)可被反復(fù)重用
兩個不同的測試函數(shù)可以調(diào)用同一個fixture,并且獲得各自的運行結(jié)果。測試函數(shù)之間并不會因為調(diào)用了同一個fixture而相互之間產(chǎn)生任何影響。
示例5:
演示代碼:
import pytest @pytest.fixture() def first_number(): #fixture函數(shù),返回1 return 1 @pytest.fixture() def order(first_number): #fixture函數(shù),調(diào)用了first_number這個fixture,并且返回一個list return [first_number] def test_secondnum1(order): #調(diào)用order,并且在order返回的list中添加 2 這個元素 order.append(2) print(order) assert order==[1,2] #斷言 def test_secondnum2(order): #也調(diào)用了order,并在order返回的list中添加 3 這個元素 order.append(3) print(order) assert order==[1,3] #斷言
運行結(jié)果:

上面這段代碼我們聲明了:
兩個fixture——first_number和order。first_number有一個返回值: 1 ;order調(diào)用了first_number,并返回一個列表: [1] 。
我們還定義了:
兩個測試函數(shù)——test_secondnum1和test_secondnum2,這兩個測試函數(shù)都調(diào)用了order。
test_secondnum1對order的返回值做了一個append(2)的操作;test_secondnum1對order的返回值做了一個append(3)的操作。
根據(jù)運行結(jié)果我們可以看出,兩個測試函數(shù)對調(diào)用的fixture都做出了各自的操作,并且得到各自的一個運行結(jié)果。兩者的運行結(jié)果沒有因為都調(diào)用了order而相互產(chǎn)生影響。
fixture可被反復(fù)重用這一特點,對于確保測試之間彼此不受影響是非常有用的。我們可以聲明一個通用的fixture函數(shù),并使用這個特性來確保每個測試都能得到未受污染的測試數(shù)據(jù),并且能從一個干凈的初始狀態(tài)開始執(zhí)行。
2.2.3 測試函數(shù)/fixture函數(shù)可以一次調(diào)用多個fixture
文章前面我們有介紹過如何使用usefixtures來調(diào)用多個fixture,由此我們可以知道,pytest是允許測試函數(shù)和fixture函數(shù)按照自己的需求一次調(diào)用多個fixture的。
示例6:
演示代碼:
import pytest @pytest.fixture() def first_number(): #第一個fixture,返回1 return 1 @pytest.fixture() def second_number(): #第二個fixture,返回2 return 2 @pytest.fixture() def third_number(): #第三個fixture,返回1 return 3 @pytest.fixture() def order(first_number,second_number): #調(diào)用first_number 和 second_number 返回 [1,2] return [first_number,second_number] def test_case(order,third_number): #調(diào)用order 和 third_number order.append(third_number) #對 order做append的操作,將third_number的返回值加入list中 print(order) assert order==[1,2,3] #斷言
運行結(jié)果:

演示代碼中我們聲明了:
四個fixture——first_number、second_number、third_number和order;
一個測試函數(shù)——test_case。
order 調(diào)用了first_number和second_number;test_case調(diào)用了order和third_number。他們都根據(jù)自己的需求調(diào)用了多個fixture,并且正常被執(zhí)行。
2.2.4 同一測試執(zhí)行期間,fixture可被多次請求
其實在看官方文檔的時候,我有點不太理解這部分的內(nèi)容。當(dāng)時看文字的描述感覺與“fixture能夠被重復(fù)調(diào)用“這一點有沖突,但是通過官方文檔的代碼示例,我才明白這兩點其實是不沖突的。
下面我們先看一下官方示例。
示例7:
演示代碼:
import pytest @pytest.fixture def first_entry(): return "a" @pytest.fixture def order(): return [] @pytest.fixture def append_first(order, first_entry): return order.append(first_entry) def test_string_only(append_first,order, first_entry): print(order) assert order == [first_entry]
運行結(jié)果:

示例代碼中聲明了:
三個fixture函數(shù)——first_entry、order和append_first;
一個測試函數(shù)——test_string_only。
first_entry返回了一個str: "a";order返回一個空list:[];append_first調(diào)用了first_entry和order,并且返回 order.append(first_entry)。
test_string_only調(diào)用了first_entry、order和append_first,并做了一個打印order值的操作和斷言操作。
通過運行結(jié)果我們可以看到,test_string_only斷言成功,并且打印的order的值是['a']。
如果按照”fixture能夠被重復(fù)調(diào)用“這一特點看,打印的order不應(yīng)該是空list的嗎?為什么會是[‘a(chǎn)']呢?
test_string_only在執(zhí)行期間,先執(zhí)行append_first,而append_first調(diào)用了order,并且對order進(jìn)行了添加元素的操作,更改了order的值,此時order返回的值會存在緩存中。當(dāng)test_string_only后面再去”調(diào)用“order的時候,其實和append_first引用的是同一個order對象,因此測試斷言才會成功。
通過pytest官方文檔我們知道,pytest一次只緩存一個fixture的實例,這意味著在使用參數(shù)化fixture時,pytest可以在給定范圍內(nèi)多次調(diào)用一個fixture。
當(dāng)測試過程中先調(diào)用的fixture對其他fixture有依賴關(guān)系的話,在調(diào)用這個fixture的時候它所依賴的fixture也會被調(diào)用。所以后面測試執(zhí)行過程中,如果再次有請求到這些fixture的話,fixture就不會被再次執(zhí)行,此時會直接從緩存中獲取到之前fixture執(zhí)行后返回的數(shù)據(jù)來使用。
“fixture能夠被重復(fù)調(diào)用“——針對不同的測試過程,目的是為了保障每個測試執(zhí)行時都是一個干凈的環(huán)境。
“同一測試執(zhí)行期間,fixture可被多次請求”——同一測試過程中,目的是為了保障在測試過程中,前后使用的數(shù)據(jù)不會被重置。
文末說明:
以上內(nèi)容是我在閱讀pytest官方文檔后,依照個人理解進(jìn)行整理。內(nèi)容可能會有理解錯誤之處,歡迎大家留言指正。謝謝
以上就是pytest自動化測試中的fixture的聲明和調(diào)用的詳細(xì)內(nèi)容,更多關(guān)于fixture聲明和調(diào)用的資料請關(guān)注本站其它相關(guān)文章!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非maisonbaluchon.cn所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。
關(guān)注官方微信