1. 程式人生 > 其它 >pytest之 fixture 實現機制

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("我是模組下的測試用例")