pytest之 fixture 實現機制
阿新 • • 發佈:2021-12-30
一、相同測試資料存放優化
在講fixture 實現機制之前,插入一段內容
上次有個小夥伴問我說,類似下面的用例程式碼情況,每條測試用例的資料都一樣的,我們可以怎麼進行優化嗎?
當然是可以的
其實我們可以把這些用例的資料全部拿出來用列表的形式存放在datas,裡面,然後遍歷每一條資料進行判斷
import pytest from Day18_pytest_fixture.login import login_check datas = [ {"user":'python37', "passwd": 'lemonban', "check": {"code": 0, "msg": "登入成功"} }, {"user":'python37', "passwd": 'lemonban666', "check": {"code": 1, "msg": "賬號或密碼不正確"} }, {"user": 'python370', "passwd": 'lemonban', "check": {"code": 1, "msg": "賬號或密碼不正確"}}, {"user": None, "passwd": 'lemonban', "check": {"code": 1, "msg": "所有的引數不能為空"}}, {"user": 'python37', "passwd": None, "check": {"code": 1, "msg": "所有的引數不能為空"}} ]
# 第二步遍歷每一條資料然後進行判斷: # 這種方法不太友好——只會執行一條用例,而且用例失敗了就不能往下繼續執行 # ——解決方法:pytest 框架自帶的解決方法:@pytest.mark.parametrize("引數名",列表資料) # class TestLogin: # def test_login_success(self): # for data in datas: # actual = login_check(data["user"],data["passwd"]) # assert actual == data["check"]
# 解決:第二步遍歷每一條資料然後進行判斷的問題 class TestLogin: @pytest.mark.parametrize("case",datas) # 解決:第二步遍歷每一條資料然後進行判斷的問題 def test_login(self,case): #這裡的case 要與上面裝飾器的case 保持一致 actual = login_check(case["user"], case["passwd"]) assert actual == case["check"]
二、fixture 實現機制
通過@pytest.fixture 裝飾器來定義fixture 。一個函式被@pytest.fixture 裝飾,那麼這個函式就是fixture。
使用fixture 時,分為兩個部分: fixture 定義、fixture 呼叫。
除此之外,還有fixture 的共享機制,巢狀呼叫機制。
1、定義fixture
(1)fixture 通過函式實現
(2)使用@pytest.fixture 進行裝飾
import pytest @pytest.fixture def init(): pass
2、fixture 的呼叫
在fixture定義好之後,可以明確:
1)fixture 處理了哪些前置準備工作、哪些後置清理工作
2)fixture 作用域(是測試函式?還是測試類,還是測試回話,還是測試模組?)
但是,注意一般情況下我們不會放在類裡面去使用,一般是放在模組或者類外面使用的
# (2)函式前面,要用@pytest.fixture來宣告它是一個fixture # autouse=True ——》有表示類下面的每條用例都會執行,沒有表示整個類只執行一次, scope="class" : 表示設定作用域 @pytest.fixture(scope="class", autouse=True) # (1)自定義一個函式名 def hello(self): # 前置準備工作的程式碼 print("一條測試用例開始執行") yield # yield之前的程式碼為:前置工作,yield之後的程式碼為:後置工作 # 後置清理工作的程式碼 print("一條測試用例執行結束")
import pytest
from Day18_pytest_fixture.login import login_check datas = [ {"user":'python37', "passwd": 'lemonban', "check": {"code": 0, "msg": "登入成功"} }, {"user":'python37', "passwd": 'lemonban666', "check": {"code": 1, "msg": "賬號或密碼不正確"} }, {"user": 'python370', "passwd": 'lemonban', "check": {"code": 1, "msg": "賬號或密碼不正確"}}, {"user": None, "passwd": 'lemonban', "check": {"code": 1, "msg": "所有的引數不能為空"}}, {"user": 'python37', "passwd": None, "check": {"code": 1, "msg": "所有的引數不能為空"}} ] # @pytest.fixture(scope="class",autouse=True) @pytest.fixture(scope="class") # (1)自定義一個函式名 def hello():# self 可以不要了,因為我們不是放在類裡面了 # 前置準備工作的程式碼 print("一條測試用例開始執行") print("======================================") yield # yield之前的程式碼為:前置工作,yield之後的程式碼為:後置工作 # 後置清理工作的程式碼 print("一條測試用例執行結束") #可以同時呼叫多個 # @pytest.fixture(scope="class") # def class_fix(): # # 前置準備工作的程式碼 # print("-----測試類下的用例開始執行------") # yield # # 後置清理工作的程式碼 # print("-----測試類下的用例執行結束------") #函式名可以隨便取 # @pytest.mark.usefixtures("class_fix") # 呼叫函式名為class_fix的fixture.
@pytest.mark.usefixtures("hello") # 呼叫函式名為hello的fixture.,注意函式名不要寫錯了,寫錯了就會報錯,因為程式找不到
#我們來思考一個問題,類怎麼去呼叫這個前後置模組的程式碼邏輯呢?——用例執行之前執行前置,用例執行之前後執行後置?——》@pytest.mark.usefixtures()
#@pytest.mark.usefixtures("hello") #pytest.mark.usefixtures("hello") 表示在執行當前類下的測試用例之前,會自動去尋找函式名叫hello的fixture並執行
class TestLogin:
@pytest.mark.parametrize("case",datas) # 解決:第二步遍歷每一條資料然後進行判斷的問題
def test_login(self,case): #這裡的case 要與上面裝飾器的case 保持一致
actual = login_check(case["user"], case["passwd"])
assert actual == case["check"]
# @pytest.mark.usefixtures("hello") #像這個是調用不了的,因為設定了作用域,只能類下面去呼叫
def test_hello_world():
print("我是模組下的測試用例")