Pytest之fixture使用詳解
一、前言
用例加setup和teardown可以實現在測試用例之前或之後加入一些操作,但是這種是整個指令碼全域性生效的,如果我想實現以下場景:
用例1需要先登入,用例2不需要登入,用例3需要先登入。很顯然這無法使用setup和teardown來實現了。
學習目標:自定義測試用例的預置條件。
二、fixture優勢
1.fixture相對於setup和teardown來說應該有以下幾點優勢:
(1)命名方式靈活,不侷限於setup和teardown這幾個命名;
(2)conftest.py 配置裡面可以實現資料共享,不需要import就能自動找到一些配置;
(3)scope="module"可以實現多個.py跨檔案共享前置;
(4)scope="session"以實現多個.py跨檔案使用一個session來完成多個用例。
fixture(scope="function", params=None, autouse=False, ids=None, name=None): """使用裝飾器標記fixture的功能 可以使用此裝飾器(帶或不帶引數)來定義fixture功能。 fixture功能的名稱可以在以後使用 引用它會在執行測試之前呼叫它:test模組或類可以使用pytest.mark.usefixtures(fixturename標記。 測試功能可以直接使用fixture名稱作為輸入引數,在這種情況下,夾具例項從fixture返回功能將被注入。 :arg scope: scope 有四個級別引數 "function" (預設), "class", "module" or "session". :arg params: 一個可選的引數列表,它將導致多個引數呼叫fixture功能和所有測試使用它 :arg autouse: 如果為True,則為所有測試啟用fixture func 可以看到它。 如果為False(預設值)則顯式需要參考來啟用fixture :arg ids: 每個字串id的列表,每個字串對應於params 這樣他們就是測試ID的一部分。 如果沒有提供ID它們將從params自動生成 :arg name: fixture的名稱。 這預設為裝飾函式的名稱。 如果fixture在定義它的同一模組中使用,夾具的功能名稱將被請求夾具的功能arg遮蔽; 解決這個問題的一種方法是將裝飾函式命名 “fixture_ <fixturename>”然後使用”@ pytest.fixture(name ='<fixturename>')“”。
三、fixture引數傳入(scpoe="function")
1.實現場景:用例1需要先登入,用例2不需要登入,用例3需要先登入
import pytest # 不帶引數時預設scope="function" @pytest.fixture() def login(): print("輸入賬號,密碼先登入") def test_s1(login): print("用例1:登入之後其他動作111") def test_s2(): # 不傳login print("用例2:不需要登入,操作222") def test_s3(login): print("用例3:登入之後其他動作333") if __name__ == "__main__": pytest.main(["-s","test_fixt.py"])
2.執行結果
2.如果@pytest.fixture()裡面沒有引數,那麼預設scope="function",也就是此時的級別的function,針對函式有效
四、conftest.py配置
1.上面一個案例是在同一個.py檔案中,多個用例呼叫同一個登陸功能,如果有多個.py的檔案都需要呼叫這個登陸功能的話,那就不能吧登入寫到用例裡面去了。
此時應該要有一個配置檔案,單獨管理一些預置的操作場景,pytest裡面預設讀取conftest.py裡面的配置。
conftest.py配置需要注意以下點:
conftest.py配置指令碼名稱是固定的,不能改名稱
conftest.py與執行的用例要在同一個pakage下,並且有init.py檔案
不需要import匯入conftest.py,pytest用例會自動查詢
conftest.py
import pytest @pytest.fixture() def login(): print("輸入賬號,密碼先登入")
test_fix1.py
import pytest
def test_s1(login): print("用例1:登入之後其他動作111") def test_s2(): # 不傳login print("用例2:不需要登入,操作222") def test_s3(login): print("用例3:登入之後其他動作333") if __name__ == "__main__": pytest.main(["-s","test_fix1.py"])
test_fix2.py
import pytest def test_s4(login): print("用例4:登入之後其他動作444") def test_s5(): print("用例5:不需要登入,操作555") if __name__ == "__main__": pytest.main(["-s","test_fix2.py"])