pytest【assert声明和检测预期异常】

一、assert 声明

使用pytest编写测试用例时,若需要传递失败消息,则可直接使用python中自带的assert关键字

如果使用了其他的测试框架,则会看到许多以assert开头的函数,下面列举了使用assert与各种以assert开头的函数的区别

pytestunittest
assert somethingassertTrue(something)
assert a == bassertEqual(a, b)
assert a <= bassertLessEqual(a, b)

pytest允许assert关键字后面添加任何表达式,如果表达式的值通过了bool转换后等于False,则意味测试失败。

import pytest

result = [(1,2,3), (3, 2, 1), ('do_something', True, 'everyday')]

@pytest.mark.test_01
def test_01_pass():
    expected = (1, 2, 3)
    assert expected == result[2]

@pytest.mark.test_03
def test_02_passing():
    ex_0 = (3, 2, 1)
    ex_1 = ('do_something', True)
    assert ex_0 == ex_1

以下展示都是assert失败的例子,可以看到回溯信息非常的丰富。

F:\TESTING\BlogPosts\ReadPytest>pytest test_one.py
================================================================================== test session starts ===================================================================================
collected 2 items                                                                                                                                                                         

test_one.py FF                                                                                                                                                                      [100%]

======================================================================================== FAILURES ========================================================================================
______________________________________________________________________________________ test_01_pass ______________________________________________________________________________________

    @pytest.mark.test_01
    def test_01_pass():
        expected = (1, 2, 3)
>       assert expected == result[2]
E       AssertionError: assert (1, 2, 3) == ('do_somethin...e, 'everyday')
E         At index 0 diff: 1 != 'do_something'
E         Use -v to get the full diff

test_one.py:16: AssertionError
____________________________________________________________________________________ test_02_passing _____________________________________________________________________________________

    @pytest.mark.test_03
    def test_02_passing():
        ex_0 = (3, 2, 1)
        ex_1 = ('do_something', True)
>       assert ex_0 == ex_1
E       AssertionError: assert (3, 2, 1) == ('do_something', True)
E         At index 0 diff: 3 != 'do_something'
E         Left contains one more item: 1
E         Use -v to get the full diff

test_one.py:22: AssertionError
================================================================================ short test summary info =================================================================================
FAILED test_one.py::test_01_pass - AssertionError: assert (1, 2, 3) == ('do_somethin...e, 'everyday')
FAILED test_one.py::test_02_passing - AssertionError: assert (3, 2, 1) == ('do_something', True)
=================================================================================== 2 failed in 0.10s ====================================================================================

上面每个失败的测试用例在行首都用一个 > 号来标识。以E 开头的行是pytest提供的额外判定信息,用于我们了解异常的具体情况。

按照错误信息中给出的建议,我们使用-v 选项来再执行一遍:

F:\TESTING\BlogPosts\ReadPytest>pytest -v test_one.py
================================================================================== test session starts ===================================================================================
collected 2 items                                                                                                                                                                         

test_one.py::test_01_pass FAILED                                                                                                                                                    [ 50%]
test_one.py::test_02_passing FAILED                                                                                                                                                 [100%]

======================================================================================== FAILURES ========================================================================================
______________________________________________________________________________________ test_01_pass ______________________________________________________________________________________

    @pytest.mark.test_01
    def test_01_pass():
        expected = (1, 2, 3)
>       assert expected == result[2]
E       AssertionError: assert (1, 2, 3) == ('do_somethin...e, 'everyday')
E         At index 0 diff: 1 != 'do_something'
E         Full diff:
E         - ('do_something', True, 'everyday')
E         + (1, 2, 3)

test_one.py:16: AssertionError
____________________________________________________________________________________ test_02_passing _____________________________________________________________________________________

    @pytest.mark.test_03
    def test_02_passing():
        ex_0 = (3, 2, 1)
        ex_1 = ('do_something', True)
>       assert ex_0 == ex_1
E       AssertionError: assert (3, 2, 1) == ('do_something', True)
E         At index 0 diff: 3 != 'do_something'
E         Left contains one more item: 1
E         Full diff:
E         - ('do_something', True)
E         + (3, 2, 1)

test_one.py:22: AssertionError
================================================================================ short test summary info =================================================================================
FAILED test_one.py::test_01_pass - AssertionError: assert (1, 2, 3) == ('do_somethin...e, 'everyday')
FAILED test_one.py::test_02_passing - AssertionError: assert (3, 2, 1) == ('do_something', True)
=================================================================================== 2 failed in 0.11s ====================================================================================

会发现展示的更一目了然了,pytest不单指出了区别,还给出了区别详情。更多assert的例子,可以在pytest.org上找到很多。


二、预期异常

为了确保测试用例在发生错误是可以抛出异常,我们使用了 with pytest.raises( expected )声明,就像下面这样:

第一次编写:
import pytest

def my_func(a):
    if type(a) is not int:
        raise TypeError('类型错误')

def test_recursion_depth():
    with pytest.raises(TypeError):
        my_func('1')
第一次运行所展示结果:
F:\TESTING\BlogPosts\ReadPytest>pytest -v test_one.py
================================================================================== test session starts ===================================================================================
collected 1 item                                                                                                                                                                          

test_one.py::test_recursion_depth PASSED                                                                                                                                            [100%]

=================================================================================== 1 passed in 0.11s ====================================================================================
第二次修改:
import pytest

def my_func(a):
    if type(a) is not int:
        raise TypeError('类型错误')

def test_recursion_depth():
    with pytest.raises(TimeoutError):
        my_func('1')

第二次运行所展示结果:
F:\TESTING\BlogPosts\ReadPytest>pytest -v test_one.py
================================================================================== test session starts ===================================================================================
collected 1 item                                                                                                                                                                          

test_one.py::test_recursion_depth FAILED                                                                                                                                            [100%]

======================================================================================== FAILURES ========================================================================================
__________________________________________________________________________________ test_recursion_depth __________________________________________________________________________________

    def test_recursion_depth():
        with pytest.raises(TimeoutError):
>           my_func('1')

test_one.py:18:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

a = '1'

    def my_func(a):
        if type(a) is not int:
>           raise TypeError('类型错误')
E           TypeError: 类型错误

test_one.py:14: TypeError
================================================================================ short test summary info =================================================================================
FAILED test_one.py::test_recursion_depth - TypeError: 类型错误
=================================================================================== 1 failed in 0.09s ====================================================================================

从以上两次运行结果来看,只要我们使用了 with pytest.raises(expected ) 声明且又符合expected异常类型,运行就会成功;当不符合我们expected 的异常类型时,就抛出别的异常 。表明运行成功就是符合我们的预期,运行失败就是跟我们所预期的不一致,测试失败 。


上面的测试中只检测了传参数据的“ 类型异常 ” ,也可以进行“ 值异常 ”检测,为校验异常消息是否符合预期,可以通过增加 as excinfo 语句得到异常消息值,再进行对比 。

import pytest

def my_func():
    raise ValueError('value属性值错误')

def test_recursion_depth():
    with pytest.raises(ValueError) as excinfo:
        my_func()
    exc_msg = excinfo.value.args[0]
    assert 'value' in exc_msg
    print('Value属性值:', excinfo.value.args)
    print('Type类型属性:', excinfo.type)
    print('捕获异常运行跟踪信息:', excinfo.traceback)
    
运行所展示结果:
ING\BlogPosts\ReadPytest>pytest -v -s test_one.py
================================================================================== test session starts ===================================================================================
collected 1 item                                                                                                                                                                          

test_one.py::test_recursion_depth Value属性值: ('value属性值错误',)
Type类型属性: <class 'ValueError'>
捕获异常运行跟踪信息: [<TracebackEntry F:\TESTING\BlogPosts\ReadPytest\test_one.py:18>, <TracebackEntry F:\TESTING\BlogPosts\ReadPytest\test_one.py:14>]
PASSED

=================================================================================== 1 passed in 0.04s ====================================================================================

现在可以更细致地观察异常,as后面的变量是ExceptionInfo类型,它会被赋予异常消息的值。我们断言也是看看预期的异常值value是不是在excinfo变量中,在就断言成功,不在就断言失败。


以上就是pytest断言和检测预期异常,如总结有不当之处,还请多多赐教,始终相信你的努力,终会在某一天得到回报!!!

在这里插入图片描述


版权声明:本文为LIFENG0402原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。