6. pytest的fixture風格的前后置

前言

  • pytest提供了更加靈活的前后置父腕,通過@pytest.fixture(scope="")來定義不同范圍的前后置

1. 如何聲明和調(diào)用fixture

  • 聲明: 使用@pytest.fixture標識的函數(shù)即可作為fixture使用
  • 調(diào)用: fixture和測試函數(shù)都可以調(diào)用书幕,只要在函數(shù)的入?yún)⒅兄苯邮褂?code>fixture的函數(shù)名稱即可
    • 代碼示例中 outer調(diào)用了orderinner蜗字,就是fixture調(diào)用fixture的例子
    • 代碼示例中 test_order調(diào)用了orderouter仑撞,就是測試函數(shù)調(diào)用fixture的例子
  • 使用@pytest.mark.usefixtures("fixture_name") 裝飾測試函數(shù)調(diào)用,需要注意的是該方法無法獲取fixture的返回值
import pytest


@pytest.fixture
def order():
    return []


@pytest.fixture(autouse=True)
def outer(order, inner):
    order.append("outer")


class TestOne:
    @pytest.fixture
    def inner(self, order):
        order.append("one")

    def test_order(self, order, outer):
        assert order == ["one", "outer"]
  • 熟悉代碼的同學可能已經(jīng)發(fā)現(xiàn)上述代碼不對辐董,outer定義的范圍內(nèi)inner未定義雾棺,理論上調(diào)用不同才對柱告,但我們執(zhí)行代碼是正常。因為pytest的執(zhí)行邏輯是以用例為中心的婆瓜,順序應該是先加載用例腳本內(nèi)容快集,當加載到測試函數(shù)時,執(zhí)行test_order廉白,發(fā)現(xiàn)它需要order函數(shù)个初,于是去調(diào)order, 調(diào)用結(jié)束后調(diào)用outer, 而在test_order調(diào)用outer時猴蹂,inner已經(jīng)被加載了院溺,所以outer可以順利的調(diào)用到inner
  • 看下執(zhí)行結(jié)果
(venv) C:\測試文件夾\project\python\pytest_demo\fixture>pytest -sv test_fixture.py
======================================================= test session starts ========================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\測試文件夾\project\python\pytest_demo, configfile: pytest.ini
collected 1 item                                                                                                                    

test_fixture.py::TestOne::test_order PASSED

======================================================== 1 passed in 0.01s =========================================================


2. 調(diào)用順序

  • fixture的調(diào)用順序取決于3個因素
    • 范圍:首先執(zhí)行更高作用域的fixture,從大到小分別為: ["session", "package", "module", "class", "function"]
    • 依賴:當一個夾具請求另一個夾具時磅轻,首先執(zhí)行另一個夾具珍逸。例如fixture_a請求fixture_b,fixture_b會先執(zhí)行瓢省,因為a依賴于b它弄息,沒有它就不能運行。即使a不需要b的結(jié)果勤婚,它仍然需要先請求b
    • 自動使用:@pytest.fixture(autouse=True)時為自動使用摹量,同一作用域(scope)內(nèi)的自動使用的fixture優(yōu)先使用。需要注意的是,如果fixture_a是自動使用且其依賴于不自動使用的fixture_b時缨称,fixture_b也會變?yōu)樽詣邮褂媚移渥鳛閒ixture_a的依賴會比fixture_a提前執(zhí)行。這也是符合調(diào)用依賴的描述的

2.1 范圍和依賴

  • 先看范圍的執(zhí)行代碼和依賴的執(zhí)行順序
# content of test_scope_dep.py
import pytest


@pytest.fixture(scope="session")
def order():
    return []


@pytest.fixture
def func(order):
    order.append("function")


@pytest.fixture(scope="class")
def cls(order):
    order.append("class")


@pytest.fixture(scope="module")
def mod(order):
    order.append("module")


@pytest.fixture(scope="package")
def pack(order):
    order.append("package")


@pytest.fixture(scope="session")
def sess(order):
    order.append("session")


class TestClass:
    def test_order(self, func, cls, mod, pack, sess, order):
        assert order == ["session", "package", "module", "class", "function"]

  • 執(zhí)行看結(jié)果, ordersess作用域都是session,但sess其依賴于order,故order先執(zhí)行
  • 其余的不同作用域的則按照順序執(zhí)行 session > package > module > class > function
(venv) C:\測試文件夾\project\python\pytest_demo\fixture>pytest -sv test_scope_dep.py
======================================================= test session starts ========================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\測試文件夾\project\python\pytest_demo, configfile: pytest.ini
collected 1 item                                                                                                                    

test_scope_dep.py::TestClass::test_order PASSED

======================================================== 1 passed in 0.01s =========================================================

2.2. 自動使用

  • 先看代碼
@pytest.fixture
def order():
    return []


@pytest.fixture
def a(order):
    order.append("a")


@pytest.fixture
def b(a, order):
    order.append("b")


@pytest.fixture(autouse=True)
def c(order):
    order.append("c")


def test_order(b, order):
    assert order == ["c", "a", "b"]
  • 執(zhí)行看結(jié)果, 所有fixture的作用域都是function,

  • 在測試時僅調(diào)用了b, 但因為c是自動使用睦尽,故c先執(zhí)行

  • c依賴于order, 所以是先調(diào)用了order再在列表中添加'c'

  • 然后調(diào)用b, b依賴于a,故先執(zhí)行a,并在列表中添加元素'a'

  • 最后執(zhí)行b,并在列表中添加'b'

  • 執(zhí)行順序 order > c > a > b

  • 注意事項

    • 盡管order是其他fixture的依賴項被調(diào)用過器净,但是測試函數(shù)中依然要主動調(diào)用,不然是無法獲取其返回值的当凡。如果order是無返回值的fixture山害,則無需調(diào)用
  • 看到此處,大家可能發(fā)現(xiàn)fixture到目前為止也僅僅是描述了前置的信息沿量,那么如何處理teardown

3. fixture聲明后置 -- yield關鍵字

# content of test_fixture_teardown.py
import pytest


@pytest.fixture
def yield_teardown():
    print('\n################  setup part ##############')
    yield True
    print('\n############## teardown part ##############')


def test_yield(yield_teardown):
    print('the case use yield_teardown result is {}'.format(yield_teardown))

  • 在yield關鍵字前的代碼為前置浪慌,yield后的代碼為后置
  • 執(zhí)行看下結(jié)果,確實按照預期打印
  • 需要注意的是朴则,這種fixture寫法中如果不需要返回值時,yield關鍵字后為空即可,但一定要有該關鍵字
(venv) C:\測試文件夾\project\python\pytest_demo\fixture>pytest -sv test_fixture_teardown.py
======================================================= test session starts ========================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\測試文件夾\project\python\pytest_demo, configfile: pytest.ini
collected 1 item                                                                                                                    

test_fixture_teardown.py::test_yield
################  setup part ##############
the case use yield_teardown result is True
PASSED
############## teardown part ##############


======================================================== 1 passed in 0.01s =========================================================


4. 參數(shù)化fixture

  • 假設一種集群測試場景权纤,有兩臺主機上需要執(zhí)行同樣的用例,那么如果在每個用例上都去寫兩個參數(shù)是不是很麻煩乌妒⌒谙耄可不可以在fixture上完成參數(shù)化,讓同一條用例根據(jù)fixture上的參數(shù)化執(zhí)行兩次撤蚊。即通過fixture的參數(shù)化實現(xiàn)所有用例的多主機測試古掏。下面以多個測試郵箱連接為例:

  • fixture函數(shù)裝飾器中增加params參數(shù)用于實現(xiàn)參數(shù)化

  • fixture函數(shù)的形參列表中增加request(固定參數(shù),不可修改)拴魄,用于接收params傳入的參數(shù)列表

  • fixture函數(shù)的內(nèi)部調(diào)用request.param即可獲得列表中的元素

# content of test_fixture_para.py
import pytest
import smtplib


@pytest.fixture(scope="module", params=["smtp.163.com", "smtp.126.com"])
def smtp_connection(request):
    smtp_connection = smtplib.SMTP(request.param, 25, timeout=5)
    yield smtp_connection
    print("\n ############### finalizing {}".format(smtp_connection))
    smtp_connection.close()


def test_fixture_param(smtp_connection):
    print('smtp_connection is {}'.format(smtp_connection))

  • 執(zhí)行一下用例
(venv) C:\測試文件夾\project\python\pytest_demo\fixture>pytest -sv test_fixture_para.py
======================================================= test session starts ========================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\測試文件夾\project\python\pytest_demo, configfile: pytest.ini
collected 2 items                                                                                                                   

test_fixture_para.py::test_fixture_param[smtp.163.com] smtp_connection is <smtplib.SMTP object at 0x03778150>
PASSED
test_fixture_para.py::test_fixture_param[smtp.126.com]
 ############### finalizing <smtplib.SMTP object at 0x03778150>
smtp_connection is <smtplib.SMTP object at 0x037781F0>
PASSED
 ############### finalizing <smtplib.SMTP object at 0x037781F0>


======================================================== 2 passed in 0.69s =========================================================
  • 假想一種接口測試的情況冗茸,通常web系統(tǒng)都需要的登錄后進行測試席镀,那么一般登錄就會放到前置中匹中,但是每個測試者或者每個測試場景中用戶名和密碼可能都不相同,那么能不能把用戶豪诲、密碼作為參數(shù)傳給前置函數(shù)顶捷,并返回認證所需數(shù)據(jù)呢,用戶名和密碼這種多個數(shù)據(jù)就需要使用dict去傳參屎篱,上代碼
@pytest.fixture(params=[{'user': 'user1', 'passwd': '1'}, {'user': 'user2', 'passwd': '2'}])
def login(request):
    user = request.param['user']
    passwd = request.param['passwd']
    token = user + passwd
    return token


def test_login(login):
    print('\nthe token is {}'.format(login))

5. conftest.py: 跨多個文件共享fixture

  • 寫到這里有人就會問服赎,這種前置只是在當前文件生效,但登錄明顯是公共的前置交播,怎么讓其共享呢重虑,name就需要使用conftest.py文件定義fixture
  • 該文件用作為整個目錄提供fixture的一種方式。在某個目錄的conftest.py文件中定義的fixture可以被該包中的任何測試用例直接使用而無需導入它們(pytest 將自動發(fā)現(xiàn)它們)
  • 每個目錄都可以有自己的conftest.py,其共享范圍為本目錄到其所有的遞歸子目錄
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秦士,一起剝皮案震驚了整個濱河市缺厉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖提针,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件命爬,死亡現(xiàn)場離奇詭異,居然都是意外死亡辐脖,警方通過查閱死者的電腦和手機饲宛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗜价,“玉大人艇抠,你說我怎么就攤上這事【米叮” “怎么了练链?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奴拦。 經(jīng)常有香客問我媒鼓,道長,這世上最難降的妖魔是什么错妖? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任绿鸣,我火速辦了婚禮,結(jié)果婚禮上暂氯,老公的妹妹穿的比我還像新娘潮模。我一直安慰自己,他們只是感情好痴施,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布擎厢。 她就那樣靜靜地躺著,像睡著了一般辣吃。 火紅的嫁衣襯著肌膚如雪动遭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天神得,我揣著相機與錄音厘惦,去河邊找鬼。 笑死哩簿,一個胖子當著我的面吹牛宵蕉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播节榜,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼羡玛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宗苍?” 一聲冷哼從身側(cè)響起稼稿,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亿遂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后渺杉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛇数,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年是越,在試婚紗的時候發(fā)現(xiàn)自己被綠了耳舅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡倚评,死狀恐怖浦徊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情天梧,我是刑警寧澤盔性,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站呢岗,受9級特大地震影響冕香,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜后豫,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一悉尾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挫酿,春花似錦构眯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葱弟,卻和暖如春壹店,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翘悉。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工茫打, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留居触,地道東北人妖混。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像轮洋,于是被迫代替她去往敵國和親制市。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359