Python Pytest自動化測試框架 fixtures

Time will tell.

一权悟、Fixture介紹

fixture是 Pytest 特有的功能酪刀,它用pytest.fixture標識储狭,定義在函數(shù)前面胚泌。在編寫測試函數(shù)的時候鞍帝,可以將此函數(shù)名稱做為傳入?yún)?shù)丈莺, Pytest 將會以依賴注入方式且预,將該函數(shù)的返回值作為測試函數(shù)的傳入?yún)?shù)蜈项。

fixture有明確的名字定硝,在其他函數(shù)瘪菌,模塊撒会,類或整個工程調用它時會被激活。

fixture是基于模塊來執(zhí)行的师妙,每個 fixture 的名字就可以觸發(fā)一個fixture的函數(shù)诵肛,它自身也可以調用其他的fixture

我們可以把fixture看做是資源默穴,在你的測試用例執(zhí)行之前需要去配置這些資源怔檩,執(zhí)行完后需要去釋放資源。比如 module類型的fixture蓄诽,適合于那些許多測試用例都只需要執(zhí)行一次的操作薛训。

fixture還提供了參數(shù)化功能,根據(jù)配置和不同組件來選擇不同的參數(shù)仑氛。

fixture主要的目的是為了提供一種可靠和可重復性的手段去運行那些最基本的測試內容许蓖。比如在測試網站的功能時,每個測試用例都要登錄和退出调衰,利用fixture就可以只做一次膊爪,否則每個測試用例都要做這兩步也是冗余。

二嚎莉、Fixture基礎實例

把一個函數(shù)定義為 Fixture 很簡單米酬,只要在函數(shù)聲明之前加上@pytest.fixture。其他函數(shù)要來調用這個Fixture趋箩,只用把它當做一個輸入的參數(shù)即可赃额。

代碼:

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    # For test purpose

結果:

(wda_python) bash-3.2$ pytest -q test_smtpsimple.py 
.F                                                                                                                                 [100%]
================================================================ FAILURES ================================================================
_________________________________________________________________ test_2 _________________________________________________________________

before = None

    def test_2(before):
        print 'test_2()'
>       assert 0    # For test purpose
E       assert 0

test_smtpsimple.py:12: AssertionError
--------------------------------------------------------- Captured stdout setup ----------------------------------------------------------

Before each test
---------------------------------------------------------- Captured stdout call ----------------------------------------------------------
test_2()
1 failed, 1 passed in 0.09 seconds
(wda_python) bash-3.2$ 

三加派、調用fixture

  1. 在測試用例中直接調用它,例如上面的基礎實例跳芳。

  2. fixture decorator調用fixture芍锦。

可以用以下3種不同的方式來寫,我只變化了函數(shù)名字和類名字飞盆,內容沒有變娄琉。

第一種是每個函數(shù)前聲明,第二種是封裝在類里吓歇,類里的每個成員函數(shù)聲明孽水,第三種是封裝在類里在前聲明。在可以看到3種不同方式的運行結果都是一樣城看。

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_3()'

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

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

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

我們用pytest -v -s test_module.py運行詳細模式測試并打印輸出:

================================================== test session starts ===================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0 -- /Users/jackey/Documents/iOS/code/iOS-Auto/MyPyEnv/wda_python/bin/python2.7
cachedir: .pytest_cache
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 6 items                                                                                                        

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

================================================ 6 passed in 0.06 seconds ================================================
(wda_python) bash-3.2$ 

  1. pytest fixture scope

fixture在創(chuàng)建的時候有一個關鍵字參數(shù) scope:

scope='session'女气,它將只運行一次,不管它在哪里定義测柠。

scope='class'表示每個類會運行一次炼鞠。

scope='module'表示每個module的所有test只運行一次。

scope='function'表示每個test都運行轰胁, scope的默認值谒主。

實例代碼:

import pytest
import time

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

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

def test_1(mod_header,func_header):
    print 'in test_1()'

def test_2(mod_header,func_header):
    print 'in test_2()'

結果:

================================================== test session starts ===================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0 -- /Users/jackey/Documents/iOS/code/iOS-Auto/MyPyEnv/wda_python/bin/python2.7
cachedir: .pytest_cache
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 2 items                                                                                                        

test_smtpsimple.py::test_1 
------------------
module   : test_smtpsimple
-------------------

------------------
function:    test_smtpsimple
time:        Sun Jan 13 12:19:25 2019
-------------------
in test_1()
PASSED
test_smtpsimple.py::test_2 
------------------
function:    test_smtpsimple
time:        Sun Jan 13 12:19:25 2019
-------------------
in test_2()
PASSED

================================================ 2 passed in 0.04 seconds ================================================
(wda_python) bash-3.2$ 

可以看到module在整個 module 中只執(zhí)行了一次。

  1. 用 autos 調用 fixture

    ixture decorator 一個 optional 的參數(shù)是autouse软吐,默認設置為False瘩将。

    當默認為False吟税,就可以選擇用上面兩種方式來試用fixture凹耙。

    當設置為True時,在一個session內的所有的test都會自動調用這個 fixture肠仪。

    權限大肖抱,責任也大,所以該功能用時也要謹慎小心异旧。

上面的例子可以這樣寫意述,效果也是一樣的:

import pytest
import time

@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.module.__name__
    print 'time:        %s' % time.asctime()
    print '-------------------'

def test_1():
    print 'in test_1()'

def test_2():
    print 'in test_2()'

結果:

================================================== test session starts ===================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0 -- /Users/jackey/Documents/iOS/code/iOS-Auto/MyPyEnv/wda_python/bin/python2.7
cachedir: .pytest_cache
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 2 items                                                                                                        

test_smtpsimple.py::test_1 
------------------
module   : test_smtpsimple
-------------------

------------------
function:    test_smtpsimple
time:        Sun Jan 13 12:34:59 2019
-------------------
in test_1()
PASSED
test_smtpsimple.py::test_2 
------------------
function:    test_smtpsimple
time:        Sun Jan 13 12:34:59 2019
-------------------
in test_2()
PASSED

================================================ 2 passed in 0.04 seconds ================================================
(wda_python) bash-3.2$ 

  1. fixture 返回值

    在上面的例子中,fixture 返回值都是默認None吮蛹,我們可以選擇讓 fixture 返回我們需要的東西荤崇。如果你的 fixture 需要配置一些數(shù)據(jù),讀個文件潮针,或者連接一個數(shù)據(jù)庫术荤,那么你可以讓 fixture 返回這些數(shù)據(jù)或資源。

    如何帶參數(shù)每篷,可以把參數(shù)賦值給params瓣戚,默認是None端圈。對于param里面的每個值,fixture都會去調用執(zhí)行一次子库,就像執(zhí)行 for 循環(huán)一樣把params里的值遍歷一次舱权。

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 session starts ===========================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0 -- /Users/jackey/Documents/iOS/code/iOS-Auto/MyPyEnv/wda_python/bin/python2.7
cachedir: .pytest_cache
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 3 items                                                                                                                        

test_smtpsimple.py::test_not_2[1] test_data: 1
PASSED
test_smtpsimple.py::test_not_2[2] test_data: 2
FAILED
test_smtpsimple.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_smtpsimple.py:9: AssertionError
=================================================== 1 failed, 2 passed in 0.09 seconds ===================================================
(wda_python) bash-3.2$ 

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

  1. conftest.py配置

    如果我們要實現(xiàn)一個測試場景: 用例1需要先登錄仑嗅, 用例2不需要先登錄宴倍,用例3需要先登錄。腳本我們可能會這樣寫:

#coding: utf-8

import pytest

@pytest.fixture()
def login():
    print '輸入賬號无畔、密碼登錄'

def test_step_1(login):
    print '用例步驟1:登錄之后其它動作111'

def test_step_2(): #不需要登錄
    print '用例步驟2: 不需要登錄啊楚, 操作222'

def test_step_3(login):
    print '用例步驟3:登錄之后其它動作333'

if __name__ == "__main__":
    pytest.main(["-s", "test_smtpsimple.py"])

結果:

========================================================== test session starts ===========================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 3 items                                                                                                                        

test_smtpsimple.py 輸入賬號、密碼登錄
用例步驟1:登錄之后其它動作111
.用例步驟2: 不需要登錄浑彰, 操作222
.輸入賬號恭理、密碼登錄
用例步驟3:登錄之后其它動作333
.

======================================================== 3 passed in 0.05 seconds ========================================================
(wda_python) bash-3.2$ 

上面一個案例是在同一個.py文件中,多個用例調用一個登陸功能郭变,如果有多個.py的文件都需要調用這個登陸功能的話颜价,那就不能把登陸寫到用例里面去了。
此時應該要有一個配置文件诉濒,單獨管理一些預置的操作場景周伦,pytest 里面默認讀取conftest.py里面的配置

conftest.py配置需要注意以下點:

  • conftest.py配置腳本名稱是固定的,不能改名稱未荒。
  • conftest.py與運行的用例要在同一個pakage下专挪,并且有init.py文件。
  • 不需要 import 導入conftest.py片排,pytest 用例會自動查找寨腔。

conftest.py

#coding: utf-8

from test_foocompare import Foo
import pytest

@pytest.fixture()
def login():
    print '輸入賬號、密碼登錄'

test_simple.py

#coding: utf-8

import pytest

def test_step_1(login):
    print '用例步驟1:登錄之后其它動作111'

def test_step_2(): #不需要登錄
    print '用例步驟2: 不需要登錄率寡, 操作222'

def test_step_3(login):
    print '用例步驟3:登錄之后其它動作333'

if __name__ == "__main__":
    pytest.main(["-s", "test_smtps

結果:

========================================================== test session starts ===========================================================
platform darwin -- Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0
rootdir: /Users/jackey/Documents/iOS/code/iOS-Auto/Agent_Test, inifile:
collected 3 items                                                                                                                        

test_smtpsimple.py 輸入賬號迫卢、密碼登錄
用例步驟1:登錄之后其它動作111
用例步驟2: 不需要登錄, 操作222
.輸入賬號冶共、密碼登錄
用例步驟3:登錄之后其它動作333

======================================================== 3 passed in 0.04 seconds ========================================================
(wda_python) bash-3.2$ 

以上本章內容就分享到這里乾蛤,如果你對更多內容、Python自動化測試捅僵、面試題家卖、感興趣的話可以加入我們175317069一起學習。會有各項學習資源庙楚,更有行業(yè)深潛多年的技術人分析講解上荡。

祝愿你能成為一名優(yōu)秀的軟件測試工程師!

歡迎【評論】醋奠、【點贊】榛臼、【關注】~

Time will tell.(時間會證明一切)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末伊佃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沛善,更是在濱河造成了極大的恐慌航揉,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件金刁,死亡現(xiàn)場離奇詭異帅涂,居然都是意外死亡,警方通過查閱死者的電腦和手機尤蛮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門媳友,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人产捞,你說我怎么就攤上這事醇锚。” “怎么了坯临?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵焊唬,是天一觀的道長。 經常有香客問我看靠,道長赶促,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任挟炬,我火速辦了婚禮鸥滨,結果婚禮上,老公的妹妹穿的比我還像新娘谤祖。我一直安慰自己婿滓,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布泊脐。 她就那樣靜靜地躺著空幻,像睡著了一般烁峭。 火紅的嫁衣襯著肌膚如雪容客。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天约郁,我揣著相機與錄音缩挑,去河邊找鬼。 笑死鬓梅,一個胖子當著我的面吹牛供置,可吹牛的內容都是我干的。 我是一名探鬼主播绽快,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼芥丧,長吁一口氣:“原來是場噩夢啊……” “哼紧阔!你這毒婦竟也來了?” 一聲冷哼從身側響起续担,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤擅耽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后物遇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乖仇,經...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年询兴,在試婚紗的時候發(fā)現(xiàn)自己被綠了乃沙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡诗舰,死狀恐怖警儒,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情眶根,我是刑警寧澤冷蚂,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站汛闸,受9級特大地震影響蝙茶,放射性物質發(fā)生泄漏。R本人自食惡果不足惜诸老,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一隆夯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧别伏,春花似錦蹄衷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至类茂,卻和暖如春耍属,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巩检。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工厚骗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兢哭。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓领舰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子冲秽,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內容