pytest系列教程——2、pytest断言的使用

2022-06-08 15:43:28 浏览数 (2)

上一章学习了pytest的基本用法,今天学习一下断言。

assert 基本用法

unitest单元测试框架中提供了丰富的断言方法,如assertEqual()、assertIn()、assertTrue()、assertIs()等,但是pytest没有。直接使用Python的assert进行断言

代码语言:javascript复制
# MyPytest.py
import pytest

def inc(x):
    return x 1

# 判断结果不等于5
def test_inc_01():
    assert inc(3) != 5

# 判断结果等于4
def test_inc_02():
    assert inc(3) == 4

# 判断结果小于等于5
def test_inc_03():
    assert inc(3) <= 5

# 判断结果包含在列表内
def test_inc_04():
    assert inc(3)  in  [1,2,3,4]


# 判断结果不为True
def test_inc_06():
    a = 1 
    assert a ==  True
    assert a is not  True



if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

执行结果:

代码语言:javascript复制
collected 5 items

MyPytest.py .....                                                        [100%]

============================== 5 passed in 0.08s ==============================

***Repl Closed***

assert断言失败提示

当我们为了脚本报错后更容易的定位到原因时候,可以在断言的地方输出断言失败提示信息,比如:

代码语言:javascript复制
# MyPytest.py
import pytest

def division(x):
    return 100/x


def test_division_01():
    res = division(3)
    assert res == 50 , f"判断 res 为50 ,当前 res 的值为{res}" 


if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

执行结果:

代码语言:javascript复制
collected 1 item

MyPytest.py F                                                            [100%]

================================== FAILURES ===================================
______________________________ test_division_01 _______________________________

    def test_division_01():
        res = division(3)
>       assert res == 50 , f"判断 res 为50 ,当前 res 的值为{res}"
E       AssertionError: 判断 res 为50 ,当前 res 的值为33.333333333333336
E       assert 33.333333333333336 == 50

MyPytest.py:10: AssertionError
=========================== short test summary info ===========================
FAILED MyPytest.py::test_division_01 - AssertionError: 判断 res 为50 ,当前 r...
============================== 1 failed in 0.21s ==============================

***Repl Closed***

预期内异常报错断言

有时候一些场景我们明知道它会报错,也知道这种报错,是正常的预期,比如:

代码语言:javascript复制
# MyPytest.py
import pytest

def division(x):
    return 100/x


def test_division_01():
    res = division(0)


if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

执行结果:

代码语言:javascript复制
collected 1 item
MyPytest.py F                                                            [100%]

================================== FAILURES ===================================
______________________________ test_division_01 _______________________________
    def test_division_01():
>       res = division(0)
MyPytest.py:9: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
x = 0
    def division(x):
>       return 100/x
E       ZeroDivisionError: division by zero
MyPytest.py:5: ZeroDivisionError
=========================== short test summary info ===========================
FAILED MyPytest.py::test_division_01 - ZeroDivisionError: division by zero
============================== 1 failed in 0.21s ==============================

***Repl Closed***

100 0的时候报错ZeroDivisionError: division by zero。为了对这种异常场景进行断言,我们需要使用pytest.raises,用法如下:

代码语言:javascript复制
# MyPytest.py
import pytest

def division(x):
    return 100/x
    
def test_division_01():
    with pytest.raises(ZeroDivisionError) as e:
        division(0)
    assert e.type == ZeroDivisionError
    assert "division by zero" in str(e.value) 

if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

注意:断言 type 的时候,异常类型是不需要加引号的,断言 value 值的时候需转 str

非预期内异常

如果我们不知道预期异常的是什么,我们可以使用matchraise进行自定义异常

代码语言:javascript复制
# MyPytest.py
import pytest

def division(x):
    if x == 0:
        raise ValueError('value not 0 or None')
    if isinstance(x,str):
        raise TypeError('value not String')
    return 100/x


def test_division_01():
    with pytest.raises(ValueError,match = 'value not 0 or None') as e:
        division(0)
    assert e.type == ValueError
    assert "value not 0 or None" in str(e.value) 


def test_division_02():
    with pytest.raises(TypeError,match = 'value not String') as e:
        division("String")
    assert e.type == TypeError
    assert "value not String" in str(e.value) 

if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

pytest-assume插件

pytest-assume是一个可以允许pytest测试用例中执行多个失败的断言的插件。安装

pip install pytest-assume

对比assert :

代码语言:javascript复制
import pytest

def inc(x):
    return x 1

# assert断言
def test_inc_01():
    assert inc(3) == 5
    assert inc(3) == 4
    assert inc(3) == 3


# pytest.assume断言
def test_inc_02():
    pytest.assume(inc(3) == 5)
    pytest.assume(inc(3) == 4)
    pytest.assume(inc(3) == 3)


if __name__ =="__main__":
    pytest.main(['MyPytest.py'])

结果:

代码语言:javascript复制
collected 2 items

MyPytest.py FF                                                           [100%]

================================== FAILURES ===================================
_________________________________ test_inc_01 _________________________________
    def test_inc_01():
>       assert inc(3) == 5
E       assert 4 == 5
E           where 4 = inc(3)
MyPytest.py:8: AssertionError
_________________________________ test_inc_02 _________________________________

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               MyPytest.py:15: AssumptionFailure
E               >> pytest.assume(inc(3) == 5)
E               AssertionError: assert False
E               
E               MyPytest.py:17: AssumptionFailure
E               >> pytest.assume(inc(3) == 3)
E               AssertionError: assert False

D:softwarepythonlibsite-packagessix.py:718: FailedAssumption
=========================== short test summary info ===========================
FAILED MyPytest.py::test_inc_01 - assert 4 == 5
FAILED MyPytest.py::test_inc_02 - pytest_assume.plugin.FailedAssumption: 
============================== 2 failed in 0.26s ==============================
***Repl Closed***

对比发现,pytest.assume在第一个断言失败的情况下继续执行后续的断言,不会终止~

0 人点赞