pytest-assume外掛(全網最詳細解釋):多重斷言執行

語言: CN / TW / HK

背景

使用pytest進行斷言判斷的時候,為了用例的精準性,經常會多個方面進行斷言,比如如下:

斷言1:斷言響應的http的狀態

斷言2:斷言響應返回的code值

斷言3:斷言響應返回的json中的data欄位是否符合預期。

如果使用原生python的assert,就會遇到一個斷言失敗則全部失敗的情況。比如說,斷言1結果為Failed,那麼斷言2和斷言3都不會被執行。

我們希望斷言2和斷言3繼續執行,這樣我們能獲取更多的斷言結果來判斷出介面哪裡出了問題,能夠更好地進行問題定位,這時候該本文主角出現了:pytest-assume外掛。

簡介

一個可以允許pytest測試用例中執行多個失敗的斷言的外掛(即上面斷言1,斷言2,斷言3都失敗的情況下,三個斷言都能被執行)。

專案:https://github.com/astraw38/pytest-assume

說明

該外掛源自pytest-expect,並且做了一部分小的修改:

1. 支援showlocals(即pytest命令列的'-l'引數, 顯示執行過程中的區域性變數)。

2. 可以全域性使用,無需指定fixtrue裝飾器。(即任意test_xxx函式中都能用)。

3. 對斷言輸出做了一些格式上的美化。

安裝

#根據你python版本,可選擇pip3或者pip
sudo pip3(pip) install git+https://github.com/astraw38/pytest-assume.git
#或者
sudo pip3(pip) install pytest-assume

例子

1. 一個對比原生assert和pytest-assume的測試用例

#!/usr/bin/env python3
#!coding:utf-8
import pytest

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
    assert x == y  #如果這個斷言失敗,則後續都不會執行
    assert True
    assert False

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_pytest_assume(x, y):
    pytest.assume(x == y) #即使這個斷言失敗,後續仍舊執行
    pytest.assume(True)
    pytest.assume(False)

輸入:

===================================================================================== test session starts =====================================================================================
platform darwin -- Python 3.8.2, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /Users/xxx/Desktop/pytest
plugins: assume-2.4.2, ordering-0.6


collected 6 items (這裡執行了六個用例)

test_demo.py FFF [100%]

========================================================================================== FAILURES ===========================================================================================
___________________________________________________________________________________ test_simple_assume[1-1] ___________________________________________________________________________________

x = 1, y = 1

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
assert x == y
assert True
> assert False (前兩個斷言成功,第三個斷言失敗了)
E assert False




test_demo.py:9: AssertionError
___________________________________________________________________________________ test_simple_assume[1-0] ___________________________________________________________________________________

x = 1, y = 0

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
> assert x == y  (第一個斷言失敗了,後續斷言不會被執行)
E assert 1 == 0


test_demo.py:7: AssertionError
___________________________________________________________________________________ test_simple_assume[0-1] ___________________________________________________________________________________

x = 0, y = 1

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
> assert x == y  (第一個斷言失敗了,後續斷言不會被執行)
E assert 0 == 1 


test_demo.py:7: AssertionError
___________________________________________________________________________________ test_pytest_assume[1-1] ___________________________________________________________________________________

tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = None

def reraise(tp, value, tb=None):
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 1 Failed Assumptions:
E
E test_demo.py:15: AssumptionFailure
E >> pytest.assume(False)
E AssertionError: assert False (前兩個斷言成功,第三個斷言失敗了)










/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages/six.py:702: FailedAssumption
---------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------
F
___________________________________________________________________________________ test_pytest_assume[1-0] ___________________________________________________________________________________


tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = None

def reraise(tp, value, tb=None):
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 2 Failed Assumptions:
E
E test_demo.py:13: AssumptionFailure
E >> pytest.assume(x == y) (第一個斷言失敗,後續繼續執行)
E AssertionError: assert False
E
E test_demo.py:15: AssumptionFailure
E >> pytest.assume(False)
E AssertionError: assert False














/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages/six.py:702: FailedAssumption
---------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------
F
___________________________________________________________________________________ test_pytest_assume[0-1] ___________________________________________________________________________________


tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = None

def reraise(tp, value, tb=None):
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 2 Failed Assumptions:
E
E test_demo.py:13: AssumptionFailure
E >> pytest.assume(x == y) (第一個斷言失敗,後續繼續執行)
E AssertionError: assert False
E
E test_demo.py:15: AssumptionFailure
E >> pytest.assume(False)
E AssertionError: assert False














/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages/six.py:702: FailedAssumption
---------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------
F
=================================================================================== short test summary info ===================================================================================
FAILED test_demo.py::test_simple_assume[1-1] - assert False
FAILED test_demo.py::test_simple_assume[1-0] - assert 1 == 0
FAILED test_demo.py::test_simple_assume[0-1] - assert 0 == 1
FAILED test_demo.py::test_pytest_assume[1-1] - pytest_assume.plugin.FailedAssumption:
FAILED test_demo.py::test_pytest_assume[1-0] - pytest_assume.plugin.FailedAssumption:
FAILED test_demo.py::test_pytest_assume[0-1] - pytest_assume.plugin.FailedAssumption:
====================================================================================== 6 failed in 0.19s ======================================================================================









 這裡我們可以看出二者的區別了,執行差異如下:

斷言型別 1,1 1,0 0,1 結論
assert 斷言3失敗 斷言1失敗,斷言2和斷言3不執行 斷言1失敗,斷言2和斷言3不執行 assert遇到斷言失敗則停下
pytest.assume 斷言3失敗 斷言1失敗,斷言2和斷言3繼續執行 斷言1失敗,斷言2和斷言3繼續執行 pytest.assume無論斷言結果,全部執行

2. 通過上下文管理器with使用pytest-assume

#!/usr/bin/env python3#!coding:utf-8
import pytest
from pytest import assume
    
@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
    #使用上下文管理器的好處是不用顯示去try和finally捕獲異常,建議使用這種寫法,簡潔有效。
    with assume: assert x == y
    with assume: assert True
    with assume: assert False

主要注意的是,如果上下文管理器裡面包含多個斷言,則只有第一個會被執行,如

#!/usr/bin/env python3
#!coding:utf-8
import pytest
from pytest import assume
    
@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_simple_assume(x, y):
    #使用上下文管理器的好處是不用顯示去try和finally捕獲異常,建議使用這種寫法,簡潔有效。
    with assume: 
        #只有第一個斷言會被執行!
        assert x == y
        assert True
        assert False

以上就是pytest-assume外掛的詳解,部分內容參考了github專案中的示例,有問題請留言。

博主:測試生財

座右銘:專注測試與自動化,致力提高研發效能;通過測試精進完成原始積累,通過讀書理財奔向財務自由。

csdn:https://blog.csdn.net/ccgshigao

部落格園:https://www.cnblogs.com/qa-freeroad/

51cto:https://blog.51cto.com/14900374