妹子讓我看她寫的pytest者春,結(jié)果...

陸陸續(xù)續(xù)斷更好久好久了,這么久發(fā)生了很多事情清女,也思考了很多事情钱烟。突然發(fā)現(xiàn)拖延癥已經(jīng)嚴(yán)重影響到了我。

什么是拖延癥嫡丙,簡單來說就是個(gè)人選擇而已拴袭。每時(shí)每刻,面臨辛苦的選項(xiàng)與逃避的選項(xiàng)時(shí)曙博,傾向于選擇更安逸的那一個(gè)拥刻。一而再再而三,就成了拖延父泳。很早之前我就計(jì)劃專注某個(gè)方面寫一個(gè)系列般哼,但是直到今日,仍沒有結(jié)果惠窄,實(shí)在是有些慚愧蒸眠,想從新逼迫自己進(jìn)步,不知道能堅(jiān)持多久杆融。

言歸正傳楞卡,談下pytest,很多人會(huì)有疑問,網(wǎng)上都那么多pytest文章了臀晃,為什么我還要專門寫呢觉渴,其實(shí)很簡單。原因有二徽惋,第一個(gè)就是老生常談的話題了多數(shù)人寫技術(shù)博客都是通過寫來看自己掌握的進(jìn)度案淋,同時(shí)哪天有用到了,回過頭看险绘,也可以起到溫故而知新的作用踢京。第二,剛好有測試妹子給我提供了一些簡單的pytest的小案例宦棺,我也正有此意瓣距,那這篇文章就這樣來了。

先聲明:我寫的技術(shù)文主要還是以理解為主代咸,不一定專業(yè)蹈丸,如果看完還是不會(huì),那一定是我寫的不夠好呐芥。不要因?yàn)槲覍懙奶^于乏味而打消自己學(xué)習(xí)的念頭逻杖。

回到正文pytest,可能很多常寫python的人第一次聽到這個(gè)庫思瘟,它究竟有什么用呢荸百?
pytest 是一個(gè)成熟的全功能的 Python 測試工具。這里提供一份Pytest 使用手冊以及官方文檔滨攻。

pytest的特點(diǎn)

  • 簡單靈活够话,容易上手,文檔豐富光绕;
  • 支持參數(shù)化女嘲,可以細(xì)粒度地控制要測試的測試用例;
  • 能夠支持簡單的單元測試和復(fù)雜的功能測試诞帐,還可以用來做selenium/appnium等自動(dòng)化測試澡为、接口自動(dòng)化測試(pytest+requests);
  • pytest具有很多第三方插件,并且可以自定義擴(kuò)展景埃,比較好用的如pytest-selenium(集成selenium)媒至、pytest-html(完美html測試報(bào)告生成)、pytest-rerunfailures(失敗case重復(fù)執(zhí)行)谷徙、pytest-xdist(多CPU分發(fā))等拒啰;
  • 測試用例的skipxfail處理;
  • 可以很好的和CI工具結(jié)合完慧,例如jenkins等等谋旦;

安裝

  • pip安裝
pip install -U pytest
  • 驗(yàn)證安裝
pytest --version # 會(huì)展示當(dāng)前已安裝版本
  • pytest中,assert 是編寫測試的最基礎(chǔ)工具。如:
a = 1
b = 3
assert a == b

執(zhí)行結(jié)果

Traceback (most recent call last):
  File "/home/xsl/test.py", line 3, in <module>
    assert a == b
AssertionError

Pytest 查找測試策略

默認(rèn)情況下册着,pytest 會(huì)遞歸查找當(dāng)前目錄下所有以 test 開始或結(jié)尾的 Python 腳本拴孤,并執(zhí)行文件內(nèi)的所有以 test開始或結(jié)束的函數(shù)和方法。

# test_no_mark.py

def test_func1():
    assert 1 == 1

def test_func2():
    assert 1 != 1

所以甲捏,編寫pytest測試樣例非常簡單演熟,只需要按照下面的規(guī)則:

  • 測試文件以test_開頭(以_test結(jié)尾也可以)
  • 測試類以Test開頭,并且不能帶有 init 方法(注意:定義class時(shí)司顿,需要以T開頭芒粹,不然pytest是不會(huì)去運(yùn)行該class的)
  • 測試函數(shù)以test_開頭

僅用四行代碼創(chuàng)建一個(gè)簡單的測試函數(shù) 文件名為test.py

import pytest

def func(x):
    return x + 1


def test_answer():
    assert func(3) == 5

if __name__ == '__main__':
    pytest.main("-s  test.py")

執(zhí)行測試代碼結(jié)果如下,pytest將顯示錯(cuò)誤信息大溜,因?yàn)閒unc(3)未返回5:

============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/xsl, inifile:
collected 1 item

test.py F

=================================== FAILURES ===================================
_________________________________ test_answer __________________________________

    def test_answer():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)

test.py:15: AssertionError
=============================== warnings summary ===============================
None
  passing a string to pytest.main() is deprecated, pass a list of arguments instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 1 failed, 1 warnings in 0.10 seconds =====================

  • 因?yàn)槊米佑玫降氖?code>@pytest.mark.parametrize化漆,那我們就詳細(xì)講解下pytest.mark.parametrize

使用方法:@pytest.mark.parametrize('參數(shù)',list)

參數(shù)一是字符串钦奋,多個(gè)參數(shù)中間用逗號(hào)隔開
第二個(gè)參數(shù)是list座云,多組數(shù)據(jù)用元祖類型;list的每個(gè)元素都是一個(gè)元組付材,元組里的每個(gè)元素和按參數(shù)順序一一對(duì)應(yīng)

# 一個(gè)參數(shù)
@pytest.mark.parametrize('參數(shù)名'朦拖,list) 進(jìn)行參數(shù)化
# 兩個(gè)參數(shù)
@pytest.mark.parametrize('參數(shù)名1,參數(shù)名2'伞租,[(參數(shù)1_data[0], 參數(shù)2_data[0]), (參數(shù)1_data[1], 參數(shù)2_data[1])])
  • 小試牛刀
import pytest

data =[[1,1], [2,1+1], [6,2*3],]
@pytest.mark.parametrize('a, b', data)
def test_assert(a, b):
    assert a == b

if __name__ == '__main__':
    pytest.main('-q test.py')

執(zhí)行結(jié)果

...                                                                      [100%]
=============================== warnings summary ===============================
None
  passing a string to pytest.main() is deprecated, pass a list of arguments instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
3 passed, 1 warnings in 0.01 seconds

  • 傳入多個(gè)參數(shù)
import pytest

@pytest.mark.parametrize("user_nm, pass_wd",
                         [("xu", "123456"), ("ni", "123456"),
                          ("xing", "123456"), ("chen", "123456")])
def test_login(user_nm, pass_wd):
    print(user_nm + " : " + pass_wd)
    assert pass_wd == '123456'

if __name__ == '__main__':
    pytest.main('-s test.py')

執(zhí)行結(jié)果如下:

============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/xsl/gogs/dps/etl, inifile:
collected 4 items

test.py xu : 123456
.ni : 123456
.xing : 123456
.chen : 123456
.

=============================== warnings summary ===============================
None
  passing a string to pytest.main() is deprecated, pass a list of arguments instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 4 passed, 1 warnings in 0.01 seconds =====================

細(xì)心的朋友發(fā)現(xiàn)了,每次我執(zhí)行的時(shí)候會(huì)用pytest.main('-s 文件名')
其實(shí)這里的-s是可以根據(jù)不同的需求進(jìn)行替換的限佩,這里我們替換成-v葵诈,那么執(zhí)行結(jié)果就變成了

============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0 -- /usr/bin/python3.5
cachedir: .pytest_cache
rootdir: /home/xsl, inifile:
collecting ... collected 4 items

test.py::test_login[xu-123456] PASSED                                    [ 25%]
test.py::test_login[ni-123456] PASSED                                    [ 50%]
test.py::test_login[xing-123456] PASSED                                  [ 75%]
test.py::test_login[chen-123456] PASSED                                  [100%]

=============================== warnings summary ===============================
None
  passing a string to pytest.main() is deprecated, pass a list of arguments instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 4 passed, 1 warnings in 0.01 seconds =====================

  • -s: 顯示程序中的print/logging輸出
  • -v: 豐富信息模式, 輸出更詳細(xì)的用例執(zhí)行信息
  • -q: 安靜模式, 不輸出環(huán)境信息
  • -k:關(guān)鍵字匹配,用and區(qū)分:匹配范圍(文件名祟同、類名作喘、函數(shù)名)
  • -x:出現(xiàn)一條測試用例失敗就退出測試。在調(diào)試階段非常有用晕城,當(dāng)測試用例失敗時(shí)泞坦,應(yīng)該先調(diào)試通過,而不是繼續(xù)執(zhí)行測試用例砖顷。

這樣就可以寫很多個(gè)測試文件贰锁,然后在另外的文件中使用pytest.main('-s 文件名') 去執(zhí)行,又因?yàn)榍拔闹v了滤蝠,pytest會(huì)遞歸查找當(dāng)前目錄下所有以 test 開始或結(jié)尾的 Python 腳本豌熄,并執(zhí)行文件內(nèi)的所有以 test開始或結(jié)束的函數(shù)和方法。所以當(dāng)需要測試的文件特別多物咳,就可以直接另寫一個(gè)文件

import pytest

if __name__ == '__main__':
    pytest.main('-s test.py')

其實(shí)根據(jù)自己不同的需求來確定pytest.main('')括號(hào)內(nèi)的內(nèi)容锣险,比如

  • 運(yùn)行./目錄下所有(test_*.py*_test.py
pytest.main(['./'])
  • 運(yùn)行./xdj 目錄下的所有用例
pytest.main (['./xdj'])    
  • 運(yùn)行指定模塊
pytest.main (['./xdj/test01.py'])
  • 運(yùn)行test01.py中的test_login方法
pytest.main (['./xdj/test01.py::test_login']) 
  • 運(yùn)行test02.pytest2(類)的方法test_class
pytest.main (['./xdj/test02.py::test2::test_class'])
  • 匹配包含love的用例(匹配目錄名、模塊名、類名芯肤、用例名)
pytest.main (['-k','love'])
  • 匹配test.py模塊下包含hello的用例
pytest.main(['-k','hello','./xdj/test.py'])
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巷折,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子崖咨,更是在濱河造成了極大的恐慌锻拘,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掩幢,死亡現(xiàn)場離奇詭異逊拍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)际邻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門芯丧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人世曾,你說我怎么就攤上這事缨恒。” “怎么了轮听?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵骗露,是天一觀的道長。 經(jīng)常有香客問我血巍,道長萧锉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任述寡,我火速辦了婚禮柿隙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲫凶。我一直安慰自己禀崖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布螟炫。 她就那樣靜靜地躺著波附,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昼钻。 梳的紋絲不亂的頭發(fā)上掸屡,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音然评,去河邊找鬼折晦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沾瓦,可吹牛的內(nèi)容都是我干的满着。 我是一名探鬼主播谦炒,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼风喇!你這毒婦竟也來了宁改?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤魂莫,失蹤者是張志新(化名)和其女友劉穎还蹲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耙考,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谜喊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了倦始。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斗遏。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鞋邑,靈堂內(nèi)的尸體忽然破棺而出诵次,到底是詐尸還是另有隱情,我是刑警寧澤枚碗,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布逾一,位于F島的核電站,受9級(jí)特大地震影響肮雨,放射性物質(zhì)發(fā)生泄漏遵堵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一怨规、第九天 我趴在偏房一處隱蔽的房頂上張望陌宿。 院中可真熱鬧,春花似錦椅亚、人聲如沸限番。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扩灯,卻和暖如春媚赖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背珠插。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工惧磺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捻撑。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓磨隘,卻偏偏與公主長得像缤底,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子番捂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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