pytest之 fixture 實現機制
一、相同測試數據存放優化
在講 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("我是模組下的測試用例")

