(1)什么是斷言
對(duì)于測(cè)試來(lái)講欲诺,不管是功能測(cè)試,自動(dòng)化測(cè)試摹蘑,還是單元測(cè)試筹燕,一般都會(huì)預(yù)設(shè)一個(gè)正確的預(yù)期結(jié)果,而在測(cè)試執(zhí)行的過(guò)程中會(huì)得到一個(gè)實(shí)際的結(jié)果衅鹿。
測(cè)試的成功與否就是拿實(shí)際的結(jié)果與預(yù)期的結(jié)果進(jìn)行比較撒踪,這個(gè)比的過(guò)程就是斷言(assert)。
(2)Pytest斷言
- 與Unittest不同大渤,Pytest使用的是Python自帶的
assert
關(guān)鍵字來(lái)進(jìn)行斷言制妄。 -
assert
關(guān)鍵字后面可以接一個(gè)表達(dá)式,只要表達(dá)式的最終結(jié)果為T(mén)rue泵三,那么斷言通過(guò)耕捞,用例執(zhí)行則為成功衔掸,否則用例執(zhí)行失敗。
(3)Pytest的斷言方式及應(yīng)用場(chǎng)景
1)使用assert語(yǔ)句
Pytest里面的斷言實(shí)際上就是Python里面的assert
斷言方法砸脊。
比較大小與是否相等:
-
assert a == b
:判斷a等于b -
assert a !=b
:判斷a不等于b
判斷包含或不包含:
-
assert a in b
:判斷b包含a -
assert a not in b
:判斷b不包含a
提示:b可以是字符串具篇,可以是列表纬霞,元組等都可以凌埂。
對(duì)類型的判斷:
-
assert isinstance(a,int)
:判斷a是否是int類型數(shù)據(jù)。
判斷方法或者函數(shù)的返回值是否為真:
-
assert xx
:判斷xx結(jié)果為真诗芜。 -
assert not xx
:判斷xx結(jié)果不為真瞳抓。
例如
#用于判斷素?cái)?shù)
def is_prime(n):
if n <= 1:
return False
for i in range(2, n):
if n % i == 0:
return False
return True
# 判斷是否為素?cái)?shù)
def test_true():
assert is_prime(13)
# 或者不為素?cái)?shù)
assert not is_prime(13)
基本上常用的就這么幾種。
2)斷言預(yù)期的異常
將異常信息存儲(chǔ)到一個(gè)變量中伏恐,變量的類型則為異常類孩哑,包含異常的type
、value
和traceback
等信息
import pytest
def test_exception_value():
with pytest.raises(ZeroDivisionError) as zero:
1 / 0 # 此處可以是方法翠桦,也可以是表達(dá)式
# print(zero) <ExceptionInfo ZeroDivisionError('division by zero') tblen=1>
# print(zero.tb)# <traceback object at 0x0000021B6068BD48>
# print(zero.typename) # 字符串"ZeroDivisionError"
# print(zero.type) # 異常類型<class 'ZeroDivisionError'>
print(zero.traceback)
assert "division by zero" in str(zero.value)
assert zero.type == ZeroDivisionError
assert zero.typename == "ZeroDivisionError"
if __name__ == '__main__':
pytest.main()
注意:在上下文管理器的作用域中横蜒,raises代碼必須是最后一行,否則其后面的代碼將不會(huì)執(zhí)行销凑。
拓展:
如果我們不知道預(yù)期異常的是什么丛晌,我們可以使用 match 和 raise 進(jìn)行自定義異常。
給pytest.raises()
函數(shù)傳遞一個(gè)關(guān)鍵字參數(shù)match
斗幼,通過(guò)match
設(shè)置的字符串正則表達(dá)式匹配異常信息澎蛛。
和Unittest
中的TestCase.assertRaisesRegexp
方法類似。
示例:
import pytest
# myfunc函數(shù)會(huì)拋出一個(gè)異常蜕窿,
def myfunc():
raise ValueError("Exception 123 raised")
def test_match():
# pytest.raises()函數(shù)谋逻,
# 可以用元組的形式傳遞參數(shù),只需要觸發(fā)其中任意一個(gè)即可桐经。
# 通過(guò)match可以設(shè)置通過(guò)正則表達(dá)式匹配異常毁兆。
with pytest.raises((ValueError, RuntimeError), match=r'.* 123 .*') as ve:
myfunc()
# 說(shuō)明:myfunc()拋出的異常被match設(shè)置的字符串匹配到
# 也就是捕獲到了該異常。
# 然后下面是斷言阴挣,123是否包含在捕獲異常的說(shuō)明中气堕。
assert "123" in str(ve.value)
if __name__ == '__main__':
pytest.main()
(4)優(yōu)化斷言
我們可以在異常的時(shí)候,輸出一些提示信息屯吊,這樣報(bào)錯(cuò)后送巡,可以方便我們來(lái)查看原因。
示例如下:
import pytest
def func():
return 100
def test_case_666():
a = func()
assert a % 3 == 0, "判斷a是否能被3整除盒卸,當(dāng)前a的值為:%s" %a
if __name__ == '__main__':
pytest.main()
"""
運(yùn)行結(jié)果:
========沒(méi)加注釋的測(cè)試結(jié)果==========
Expected :0
Actual :1
<Click to see difference>
def test_case_666():
a = 100
> assert a % 3 == 0
E assert 1 == 0
test_01.py:55: AssertionError
Assertion failed
========添加注釋的測(cè)試結(jié)果==========
Expected :0
Actual :1
<Click to see difference>
def test_case_666():
a = 100
> assert a % 3 == 0, "判斷a是否能被3整除骗爆,當(dāng)前a的值為:%s" %a
E AssertionError: 判斷a是否能被3整除,當(dāng)前a的值為:100
E assert 1 == 0
test_01.py:53: AssertionError
Assertion failed
"""
(5)使用標(biāo)記檢查異常
@pytest.mark.xfail(raises=ZeroDivisionError)
示例:
import pytest
@pytest.mark.xfail(raises=ZeroDivisionError)
def test_exception_value():
1 / 0
if __name__ == '__main__':
pytest.main()
# 說(shuō)明代碼:
# 預(yù)期拋出ZeroDivisionError異常蔽介,
# 實(shí)際測(cè)試用例執(zhí)行也拋出了ZeroDivisionError異常摘投。
# 測(cè)試結(jié)果:該用例是xfailed