『德不孤』Pytest框架 — 8、Pytest斷言

繁華似錦Fighting發表於2022-02-27

1、什麼是斷言

對於測試來講,不管是功能測試,自動化測試,還是單元測試,一般都會預設一個正確的預期結果,而在測試執行的過程中會得到一個實際的結果。

測試的成功與否就是拿實際的結果與預期的結果進行比較,這個比的過程就是斷言(assert)。

2、Pytest斷言

  • 與Unittest不同,Pytest使用的是Python自帶的assert關鍵字來進行斷言。
  • assert關鍵字後面可以接一個表示式,只要表示式的最終結果為True,那麼斷言通過,用例執行則為成功,否則用例執行失敗。

3、Pytest的斷言方式及應用場景

(1)使用assert語句

Pytest裡面的斷言實際上就是Python裡面的assert斷言方法。

1)比較大小與是否相等:

  • assert a == b:判斷a等於b
  • assert a !=b:判斷a不等於b

2)判斷包含或不包含:

  • assert a in b:判斷b包含a
  • assert a not in b:判斷b不包含a
      提示:b可以是字串,可以是列表,元組等都可以。

3)對型別的判斷:

  • assert isinstance(a,int):判斷a是否是int型別資料。

4)判斷方法或者函式的返回值是否為真:

  • assert xx:判斷xx結果為真。
  • assert not xx:判斷xx結果不為真。

例如:

#用於判斷素數
def is_prime(n):
    if n <= 1:
        return False
    for i in range(2, n):
        if n % i == 0:
            return False
        return True


# 判斷是否為素數
def test_true():
    assert is_prime(13)
    # 或者不為素數
    assert not is_prime(13)

基本上常用的就這麼幾種。

(2)斷言預期的異常

將異常資訊儲存到一個變數中,變數的型別則為異常類,包含異常的typevaluetraceback等資訊

import pytest


def test_exception_value():
    with pytest.raises(ZeroDivisionError) as zero:
        1 / 0  # 此處可以是方法,也可以是表示式

    # 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程式碼必須是最後一行,否則其後面的程式碼將不會執行。

(3)擴充

如果我們不知道預期異常的是什麼,我們可以使用 matchraise 進行自定義異常。

pytest.raises()函式傳遞一個關鍵字引數match,通過match設定的字串正規表示式匹配異常資訊。

Unittest中的TestCase.assertRaisesRegexp方法類似。

示例:

import pytest


# myfunc函式會丟擲一個異常,
def myfunc():
    raise ValueError("Exception 123 raised")


def test_match():
    # pytest.raises()函式,
    # 可以用元組的形式傳遞引數,只需要觸發其中任意一個即可。
    # 通過match可以設定通過正規表示式匹配異常。
    with pytest.raises((ValueError, RuntimeError), match=r'.* 123 .*') as ve:
        myfunc()
        # 說明:myfunc()丟擲的異常被match設定的字串匹配到
        # 也就是捕獲到了該異常。
        # 然後下面是斷言,123是否包含在捕獲異常的說明中。

    assert "123" in str(ve.value)


if __name__ == '__main__':
    pytest.main()

4、優化斷言

我們可以在異常的時候,輸出一些提示資訊,這樣報錯後,可以方便我們來檢視原因。

示例如下:

import pytest

def func():
    return 100

def test_case_666():
    a = func()
    assert a % 3 == 0, "判斷a是否能被3整除,當前a的值為:%s" %a


if __name__ == '__main__':
    pytest.main()

"""
執行結果:

========沒加註釋的測試結果==========
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


========新增註釋的測試結果==========
Expected :0
Actual   :1
<Click to see difference>

def test_case_666():
        a = 100
>       assert a % 3 == 0, "判斷a是否能被3整除,當前a的值為:%s" %a
E       AssertionError: 判斷a是否能被3整除,當前a的值為:100
E       assert 1 == 0

test_01.py:53: AssertionError

Assertion failed
"""

5、使用標記檢查異常

使用註釋:@pytest.mark.xfail(raises=ZeroDivisionError)

示例:

import pytest

@pytest.mark.xfail(raises=ZeroDivisionError)
def test_exception_value():
    1 / 0

if __name__ == '__main__':
    pytest.main()

# 說明程式碼:
# 預期丟擲ZeroDivisionError異常,
# 實際測試用例執行也丟擲了ZeroDivisionError異常。
# 測試結果:該用例是xfailed

相關文章