pytest 使用fixture給測試函數傳參


fixture主要用於測試函數傳參和前置后置操作

 

一,fixture當參數傳入

 

fixture可以當做參數傳入,定義fixture跟定義普通函數差不多,唯一區別就是在函數上加個裝飾器@pytest.fixture()
fixture命名不要以test開頭,跟用例區分開
fixture是有返回值的,沒有返回值默認為None
用例調用fixture的返回值,直接就是把fixture的函數名稱當做變量名稱。

@pytest.fixture()
def creat_id():
a=2
return a*3

def test_compute(creat_id):
some=creat_id+4
assert some==11

 

creat_id = 6

def test_compute(creat_id):
some=creat_id+4
> assert some==11
E assert 10 == 11
test_study.py:42: AssertionError

 


在這里故意用例執行失敗,通過回溯可以看到
1,test_compute測試函數需要一個名為的函數參數creat_id,通過查找名為的帶有fixture標記的函數,可以找到匹配的夾具函數creat_id
2,creat_id() 被稱為創建實例,得到creat_id=6
3,test_compute函數開始執行,斷言失敗

當fixture標記的函數沒有返回值時,執行用例,改fixture標記函數返回值默認為None

creat_id = None

def test_compute(creat_id):
> some=creat_id+4
E TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
test_study.py:41: TypeError

 


如果想要實現該creat_id函數能夠被其他模塊/類等共享使用,可以把寫入到conftest.py文件,並寫上scope對應的值,對於可能的值scope有:function,class,module,package或session。不填寫默認function

二,多個fixture使用

 


1.如果用例需要用到多個fixture的返回數據,fixture也可以返回一個元祖,list或字典,然后從里面取出對應數據。

@pytest.fixture()
def creat_id():
return {'a':2*3,'b':2+3}

def test_compute(creat_id):
some=creat_id['a']+4
some2 = creat_id['b'] + 4
assert some==11
assert some2 == 11

 


執行用例,可以看到creat_id得到一個字典,然后再分別取值

creat_id = {'a': 6, 'b': 5}

def test_compute(creat_id):
some=creat_id['a']+4
some2 = creat_id['b'] + 4
> assert some==11
E assert 10 == 11
test_study.py:41: AssertionError

 


2.也可以分成多個fixture,然后在用例中傳多個fixture參數

@pytest.fixture()
def creat_id():
return 2*3

@pytest.fixture()
def creat_id2():
return 2+3

def test_compute(creat_id,creat_id2):
some=creat_id+4
some2 = creat_id2 + 4
assert some==11
assert some2 == 11

 

執行用例,可以看到creat_id = 6, creat_id2 = 5

creat_id = 6, creat_id2 = 5

def test_compute(creat_id,creat_id2):
some=creat_id+4
some2 = creat_id2 + 4
> assert some==11
E assert 10 == 11
test_study.py:46: AssertionError

 


三,fixture互相調用

 


將定義為fixture的方法的返回值用在其他方法中

四,fixture的作用范圍

 


fixture里面有個scope參數可以控制fixture的作用范圍:

@pytest.fixture(scope='function')
1
session>module>class>function
-function:每一個函數或方法都會調用,默認情況下是function
-class:每一個類調用一次,一個類中可以有多個方法
-module:每一個.py文件調用一次,該文件內又有多個function和class
-session:是多個文件調用一次,可以跨.py文件調用,每個.py文件就是module

注:
fixture為session級別是可以跨.py模塊調用的,也就是當我們有多個.py文件的用例的時候,如果多個用例只需調用一次fixture,那就可以設置為scope=“session”,並且寫到conftest.py文件里。
conftest.py文件名稱時固定的,pytest會自動識別該文件。放到項目的根目錄下就可以全局調用了,如果放到某個package下,那就在該ackage內有效

scope越大,實例化越早
1.當函數調用多個fixtures的時候,scope較大的(比如session)實例化早於scope較小的(比如function或者class)
2.同樣scope的順序則按照其在測試函數中定義的順序及依賴關系來實例化

fixture源碼詳解
fixture(scope=‘function’,params=None,autouse=False,ids=None,name=None):
scope:有四個級別參數"function"(默認),“class”,“module”,“session”
params:一個可選的參數列表,它將導致多個參數調用fixture功能和所有測試使用它。
autouse:如果True,則為所有測試激活fixture func可以看到它。如果為False則顯示需要參考來激活fixture
ids:每個字符串id的列表,每個字符串對應於params這樣他們就是測試ID的一部分。如果沒有提供ID它們將從params自動生成
name:fixture的名稱。這默認為裝飾函數的名稱。如果fixture在定義它的統一模塊中使用,夾具的功能名稱將被請求夾具的功能arg遮蔽,解決這個問題的一種方法時將裝飾函數命令"fixture_“然后使用”@pytest.fixture(name=’’)"。

五,調用fixture的四種方法

 


1.函數或類里面方法直接傳fixture的函數參數名稱@pytest.fixture()

 

@pytest.fixture()
def test1():
print('\n開始執行function')

def test_a(test1):
print('---用例a執行---')

#執行結果
開始執行function
---用例a執行---

 


2.使用裝飾器@pytest.mark.usefixtures()修飾需要運行的用例,該方式獲取不到fixture標識函數的返回值


如:@pytest.mark.usefixtures('test1')

@pytest.fixture()
def test1():
print('\n開始執行function')

@pytest.mark.usefixtures('test1')
def test_a():
print('---用例a執行---')

#執行結果
開始執行function
---用例a執行---

 

usefixtures與傳fixture區別
usefixture,無法獲取到返回值。傳fixture,可以獲取到返回值。
所以當fixture需要用到return出來的參數時,只能使用傳fixture方式,當不需要用到return出來的參數時,兩種方式都可以。

 

3.疊加usefixtures


如果一個方法或者一個class用例想要同時調用多個fixture,可以使用
@pytest.mark.usefixtures()進行疊加。
注意疊加順序,先執行的放底層,后執行的放上層。
如:先執行test2 再執行test1

@pytest.mark.usefixtures('test1')
@pytest.mark.usefixtures('test2')
def test_xx(): #測試用例
pass

 


4.autouse設置為True,自動調用fixture功能


設置scope為module級別,在當前.py用例模塊只執行一次,autouse=True自動使用
設置scope為function級別,每個用例前都調用一次,自動使用
如:@pytest.fixture(scope="module", autouse=True)

六,fixture使用yield實現setup和teardown
可以通過使用yield語句代替return,fixture里面的teardown用yield來喚醒teardown的執行,yield語句之后的所有代碼都將用作拆卸代碼

@pytest.fixture(scope="module")
def open():
print("\n1,打開瀏覽器,並且打開百度首頁") #實現setup
yield 10 #“yield 10”替代“return 10”,且實現teardown
print("\n2,執行teardown!")
print("3,最后關閉瀏覽器")

def test_compute2(open):
assert open==10

def test_compute3(open):
assert open==9

 

執行時加上“-s -q”命令,可以發現,scope="module"代表每個模塊調用一次,調用時先執行open中的第一行打印代碼,然后yield 10返回數值9給測試函數使用,當兩個測試函數都執行完畢后(一個成功一個失敗),再執行yield后面的兩行打印代碼

1,打開瀏覽器,並且打開百度首頁
.F
2,執行teardown!
3,最后關閉瀏覽器

 



yield遇到異常:
1.如果其中一個用例出現異常,不影響yield后面的teardown執行,運行結果互不影響,並且在用例全部執行完之后,會呼喚teardown的內容
2.如果在setup就異常了,那么是不會去執行yield后面的teardown內容了

七,使用帶有參數化fixture
與在@ pytest.mark.parametrize中使用的方式相同,用於在參數化燈具的值集中應用標記。在fixture中使用params參數
是一個可選的參數列表,它將導致多個參數調用fixture功能和所有測試使用它。如:
@pytest.fixture(params=[0, 1)
然后被fixture標記的函數需要使用request中的request.param才能使用到params中的值
1,

@pytest.fixture(params=[3,4,5, pytest.param(2, marks=pytest.mark.skip)])
def creat_id(request):
print('打印param的值',request.param)
return request.param+3

def test_compute(creat_id):
assert creat_id==6

 


執行時加‘-v’命令,可以看到每次測試函數的情況,
運行此測試將跳過對creat_id函數中value 的調用“2”,最后test_compute一共執行了3次,分別使用了creat_id函數的三個值,每次得到一個參數值;跳過1條

test_study.py::test_compute[3] 打印param的值 3
PASSED
test_study.py::test_compute[4] 打印param的值 4
FAILED
test_study.py::test_compute[5] 打印param的值 5
FAILED
test_study.py::test_compute[2] SKIPPED

 


六,在各個級別上覆蓋fixture


1.一個工程下可以建多個conftest.py的文件,一般在工程根目錄下設置的conftest文件起到全局作用。在不同子目錄下也可以放conftest.py的文件,作用范圍只能在該層級以及以下目錄生效。
2.conftest在不同的層級間的作用域不一樣,再執行某模塊時,先執行這個模塊對應的祖先目錄是否有conftest文件,然后依次往下級目錄查找

3.conftest是不能跨模塊調用的
4.conftest.py與運行的用例要在同一個pakage下,並且有init.py文件
注意:
Pytest對於每個fixture只會緩存一個實例,這意味着如果使用參數化的fixture,pytest可能會比定義的作用域更多次的調用fixture函數(因為需要創建不同參數的fixture)

可以使用pytest --fixtures xx.py 來查看可用的fixture
在相對較大的測試套件中,很可能需要override一個global或root一個已locally 定義的夾具,以保持測試代碼的可讀性和可維護性。

1,在文件夾級別(通過conftest文件)重寫fixtures方法
如在/test1/conftest.py和/test1/test2/conftest.py中都有一個被fixture標識的同名方法:
則/test1/路徑下的測試模塊使用conftest.py中的的fixture方法,
而/test1/test2/路徑下的測試模塊會使用fixture.py文件中重寫的fixture方法

test1/
__init__.py
conftest.py
#test1/ conftest.py
import pytest
@pytest.fixture
def username():
return 'username'
test_something.py
# test1/test_something.py
def test_username(username):
assert username == 'username'

test2/
__init__.py
conftest.py
# test1/test2/conftest.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-' + username
test_something.py
# test1/test2/test_something.py
def test_username(username):
assert username == 'overridden-username'

 


2,在測試模塊級別重寫fixtures方法
如在/test1/conftest.py都有一個被fixture標識的同名方法:username()
/test1路徑下有一測試模塊test_something.py,重寫了fixtures方法1:username()
/test1路徑下有一測試模塊test_something_else.py,重寫了fixtures方法2:username()
這兩個文件分別使用自己的fixtures方法:username()

test1/
__init__.py
conftest.py
# test1/conftest.py
import pytest
@pytest.fixture
def username():
return 'username'

test_something.py
# test1/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
# test1/test_something_else.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-else-' + username
def test_username(username):
assert username == 'overridden-else-username'

 


總結:
fixtures方法的查找方法
先從根目錄下的fixture.py文件中查找,
依次往次級目錄的fixture.py文件中查找,
最后再查找當前測試模塊py文件中是否有該fixtures方法,使用最近的一個fixtures方法
注:同一個py文件中可以有同名的fixtures方法,也是使用最近的一個

原文鏈接:https://blog.csdn.net/shuyaoyao/article/details/101103671


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM