Pytest高級進(jìn)階之Fixture

一. fixture介紹

fixture是pytest的一個(gè)閃光點(diǎn)议纯,pytest要精通怎么能不學(xué)習(xí)fixture呢?跟著我一起深入學(xué)習(xí)fixture吧耕肩。其實(shí)unittest和nose都支持fixture那槽,但是pytest做得更炫。
fixture是pytest特有的功能鳞芙,它用pytest.fixture標(biāo)識,定義在函數(shù)前面期虾。在你編寫測試函數(shù)的時(shí)候原朝,你可以將此函數(shù)名稱做為傳入?yún)?shù),pytest將會以依賴注入方式镶苞,將該函數(shù)的返回值作為測試函數(shù)的傳入?yún)?shù)喳坠。
fixture有明確的名字,在其他函數(shù)茂蚓,模塊壕鹉,類或整個(gè)工程調(diào)用它時(shí)會被激活。
fixture是基于模塊來執(zhí)行的聋涨,每個(gè)fixture的名字就可以觸發(fā)一個(gè)fixture的函數(shù)晾浴,它自身也可以調(diào)用其他的fixture。
我們可以把fixture看做是資源牍白,在你的測試用例執(zhí)行之前需要去配置這些資源脊凰,執(zhí)行完后需要去釋放資源。比如module類型的fixture茂腥,適合于那些許多測試用例都只需要執(zhí)行一次的操作狸涌。
fixture還提供了參數(shù)化功能切省,根據(jù)配置和不同組件來選擇不同的參數(shù)。
fixture主要的目的是為了提供一種可靠和可重復(fù)性的手段去運(yùn)行那些最基本的測試內(nèi)容帕胆。比如在測試網(wǎng)站的功能時(shí)朝捆,每個(gè)測試用例都要登錄和退出迟几,利用fixture就可以只做一次亲铡,否則每個(gè)測試用例都要做這兩步也是冗余。

下面會反復(fù)提高Python的Module概念捉腥,Python中的一個(gè)Module對應(yīng)的就是一個(gè).py文件歼捐。其中定義的所有函數(shù)或者是變量都屬于這個(gè)Module。這個(gè)Module 對于所有函數(shù)而言就相當(dāng)于一個(gè)全局的命名空間晨汹,而每個(gè)函數(shù)又都有自己局部的命名空間豹储。

二. Fixture基礎(chǔ)實(shí)例入門

把一個(gè)函數(shù)定義為Fixture很簡單,只能在函數(shù)聲明之前加上“@pytest.fixture”淘这。其他函數(shù)要來調(diào)用這個(gè)Fixture剥扣,只用把它當(dāng)做一個(gè)輸入的參數(shù)即可。
test_fixture_basic.py

import pytest

@pytest.fixture()
def before():
    print '\nbefore each test'

def test_1(before):
    print 'test_1()'

def test_2(before):
    print 'test_2()'
    assert 0

下面是運(yùn)行結(jié)果铝穷,test_1和test_2運(yùn)行之前都調(diào)用了before钠怯,也就是before執(zhí)行了兩次。默認(rèn)情況下曙聂,fixture是每個(gè)測試用例如果調(diào)用了該fixture就會執(zhí)行一次的晦炊。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v -s test_fixture_basic.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

test_fixture_basic.py::test_1
before each test
test_1()
PASSED
test_fixture_basic.py::test_2
before each test
test_2()
FAILED

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

before = None

    def test_2(before):
        print 'test_2()'
>       assert 0
E       assert 0

test_fixture_basic.py:12: AssertionError
===================== 1 failed, 1 passed in 0.23 seconds ======================

如果你的程序出現(xiàn)了下面的錯(cuò)誤,就是開始忘記添加‘import pytest',所以不要忘記羅宁脊。

=================================== ERRORS ====================================
_________________ ERROR collecting test_fixture_decorator.py __________________
test_fixture_decorator.py:2: in <module>
    @pytest.fixture()
E   NameError: name 'pytest' is not defined
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.36 seconds ===========================

三. 調(diào)用fixture的三種方式

1. 在測試用例中直接調(diào)用它断国,例如第二部分的基礎(chǔ)實(shí)例。

2. 用fixture decorator調(diào)用fixture

可以用以下三種不同的方式來寫榆苞,我只變化了函數(shù)名字和類名字稳衬,內(nèi)容沒有變。第一種是每個(gè)函數(shù)前聲明坐漏,第二種是封裝在類里薄疚,類里的每個(gè)成員函數(shù)聲明,第三種是封裝在類里在前聲明赊琳。在可以看到3中不同方式的運(yùn)行結(jié)果都是一樣街夭。
test_fixture_decorator.py

import pytest

@pytest.fixture()
def before():
    print('\nbefore each test')

@pytest.mark.usefixtures("before")
def test_1():
    print('test_1()')

@pytest.mark.usefixtures("before")
def test_2():
    print('test_2()')

class Test1:
    @pytest.mark.usefixtures("before")
    def test_3(self):
        print('test_1()')

    @pytest.mark.usefixtures("before")
    def test_4(self):
        print('test_2()')

@pytest.mark.usefixtures("before")
class Test2:
    def test_5(self):
        print('test_1()')

    def test_6(self):
        print('test_2()')

運(yùn)行結(jié)果如下,和上面的基礎(chǔ)實(shí)例的運(yùn)行效果一樣躏筏。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v -s test_fixture_decorator.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 6 items 

test_fixture_decorator.py::test_1
before each test
test_1()
PASSED
test_fixture_decorator.py::test_2
before each test
test_2()
PASSED
test_fixture_decorator.py::Test1::test_3
before each test
test_1()
PASSED
test_fixture_decorator.py::Test1::test_4
before each test
test_2()
PASSED
test_fixture_decorator.py::Test2::test_5
before each test
test_1()
PASSED
test_fixture_decorator.py::Test2::test_6
before each test
test_2()
PASSED

========================== 6 passed in 0.10 seconds ===========================

3. 用autos調(diào)用fixture

fixture decorator一個(gè)optional的參數(shù)是autouse, 默認(rèn)設(shè)置為False莱坎。
當(dāng)默認(rèn)為False,就可以選擇用上面兩種方式來試用fixture寸士。
當(dāng)設(shè)置為True時(shí)檐什,在一個(gè)session內(nèi)的所有的test都會自動調(diào)用這個(gè)fixture碴卧。
權(quán)限大,責(zé)任也大乃正,所以用該功能時(shí)也要謹(jǐn)慎小心住册。

import time
import pytest

@pytest.fixture(scope="module", autouse=True)
def mod_header(request):
    print('\n-----------------')
    print('module      : %s' % request.module.__name__)
    print('-----------------')

@pytest.fixture(scope="function", autouse=True)
def func_header(request):
    print('\n-----------------')
    print('function    : %s' % request.function.__name__)
    print('time        : %s' % time.asctime())
    print('-----------------')

def test_one():
    print('in test_one()')

def test_two():
    print('in test_two()')

從下面的運(yùn)行結(jié)果,可以看到mod_header在該module內(nèi)運(yùn)行了一次瓮具,而func_header對于每個(gè)test都運(yùn)行了一次荧飞,總共兩次。該方式如果用得好名党,還是可以使代碼更為簡潔叹阔。
但是對于不熟悉自己組的測試框架的人來說,在pytest里面去新寫測試用例传睹,需要去了解是否已有一些fixture是module或者class級別的需要注意耳幢。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v -s test_fixture_auto.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

test_fixture_auto.py::test_one
-----------------
module      : test_fixture_auto
-----------------

-----------------
function    : test_one
time        : Sat Mar 18 06:56:54 2017
-----------------
in test_one()
PASSED
test_fixture_auto.py::test_two
-----------------
function    : test_two
time        : Sat Mar 18 06:56:54 2017
-----------------
in test_two()
PASSED

========================== 2 passed in 0.03 seconds ===========================

四. fixture scope

function:每個(gè)test都運(yùn)行,默認(rèn)是function的scope
class:每個(gè)class的所有test只運(yùn)行一次
module:每個(gè)module的所有test只運(yùn)行一次
session:每個(gè)session只運(yùn)行一次

比如你的所有test都需要連接同一個(gè)數(shù)據(jù)庫欧啤,那可以設(shè)置為module睛藻,只需要連接一次數(shù)據(jù)庫,對于module內(nèi)的所有test邢隧,這樣可以極大的提高運(yùn)行效率店印。

五. fixture 返回值

在上面的例子中,fixture返回值都是默認(rèn)None倒慧,我們可以選擇讓fixture返回我們需要的東西按摘。如果你的fixture需要配置一些數(shù)據(jù),讀個(gè)文件纫谅,或者連接一個(gè)數(shù)據(jù)庫院峡,那么你可以讓fixture返回這些數(shù)據(jù)或資源。

如何帶參數(shù)
fixture還可以帶參數(shù)系宜,可以把參數(shù)賦值給params照激,默認(rèn)是None。對于param里面的每個(gè)值盹牧,fixture都會去調(diào)用執(zhí)行一次俩垃,就像執(zhí)行for循環(huán)一樣把params里的值遍歷一次。
test_fixture_param.py

import pytest

@pytest.fixture(params=[1, 2, 3])
def test_data(request):
    return request.param

def test_not_2(test_data):
    print('test_data: %s' % test_data)
    assert test_data != 2

可以看到test_not_2里面把用test_data里面定義的3個(gè)參數(shù)運(yùn)行里三次汰寓。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v -s test_fixture_param.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 3 items 

test_fixture_param.py::test_not_2[1] test_data: 1
PASSED
test_fixture_param.py::test_not_2[2] test_data: 2
FAILED
test_fixture_param.py::test_not_2[3] test_data: 3
PASSED

================================== FAILURES ===================================
________________________________ test_not_2[2] ________________________________

test_data = 2

    def test_not_2(test_data):
        print('test_data: %s' % test_data)
>       assert test_data != 2
E       assert 2 != 2

test_fixture_param.py:9: AssertionError
===================== 1 failed, 2 passed in 0.24 seconds ======================

本文對pytest的fixture進(jìn)行了深入的講解和練習(xí)口柳,希望讀者能夠把fixture這些高級功能都用到平時(shí)的pytest功能中,提高運(yùn)行效率有滑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跃闹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌望艺,老刑警劉巖苛秕,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異找默,居然都是意外死亡艇劫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門惩激,熙熙樓的掌柜王于貴愁眉苦臉地迎上來店煞,“玉大人,你說我怎么就攤上這事风钻∏牦埃” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵骡技,是天一觀的道長鸣个。 經(jīng)常有香客問我,道長哮兰,這世上最難降的妖魔是什么毛萌? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任苟弛,我火速辦了婚禮喝滞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘膏秫。我一直安慰自己右遭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布缤削。 她就那樣靜靜地躺著窘哈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亭敢。 梳的紋絲不亂的頭發(fā)上滚婉,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音帅刀,去河邊找鬼让腹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扣溺,可吹牛的內(nèi)容都是我干的骇窍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼锥余,長吁一口氣:“原來是場噩夢啊……” “哼腹纳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤嘲恍,失蹤者是張志新(化名)和其女友劉穎足画,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛔钙,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锌云,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吁脱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桑涎。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖兼贡,靈堂內(nèi)的尸體忽然破棺而出攻冷,到底是詐尸還是另有隱情,我是刑警寧澤遍希,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布等曼,位于F島的核電站,受9級特大地震影響凿蒜,放射性物質(zhì)發(fā)生泄漏禁谦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一废封、第九天 我趴在偏房一處隱蔽的房頂上張望州泊。 院中可真熱鬧,春花似錦漂洋、人聲如沸遥皂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽演训。三九已至,卻和暖如春贝咙,著一層夾襖步出監(jiān)牢的瞬間样悟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工庭猩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窟她,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓眯娱,卻偏偏與公主長得像礁苗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子徙缴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容