1. pytest的异常处理和断言

万事都从异常开始,pytest也让我们从异常开始吧

前置条件

  • 确认pytest完成安装
    pip install pytest

1. 先看第一条用例

# content of test_1.py
import pytest


def f():
    return 3


def test_function():
    assert f() != 4

执行这条用例,进入用例所在目录,执行pytest -sv test_1.py,稍后再解释pytest命令行所有的参数

(venv) C:\测试文件夹\project\python\pytest_demo> pytest -sv test_1.py
======================================================================================= test session starts =======================================================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                                                                                                                   

test_1.py::test_function PASSED

======================================================================================== 1 passed in 0.01s ========================================================================================

2. 断言不总是成功,出现异常如何处理,尤其是当该异常是我们故意构造的异常。

  • 修改test_function中的代码的!===
    再次执行:
(venv) C:\测试文件夹\project\python\pytest_demo>pytest -sv test_1.py
=============================================== test session starts ================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.e
xe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                                    
test_1.py::test_function FAILED
===================================================== FAILURES =====================================================
__________________________________________________ test_function ___________________________________________________
    def test_function():
>       assert f() == 4
E       assert 3 == 4
E         +3
E         -4
test_1.py:9: AssertionError
============================================= short test summary info ==============================================
FAILED test_1.py::test_function - assert 3 == 4
================================================ 1 failed in 0.11s =================================================

3. 处理异常

  • pytest自带异常处理方式,可以使用
with pytest.raises(ZeroDivisionError) as exception_info:
    pass
  • 其中exception_info有3个关键属性会经常用到:.type, .value, .typename
  • 分别为异常的类型,异常的msg信息,异常的名称

4. 在步骤1的文件中添加以下代码:

def test_f2():
    with pytest.raises(NameError) as exception_info:
        f2()
    print()
    print('error type is {}'.format(exception_info.type))
    print('error typename is {}'.format(exception_info.typename))
    print('error message is {}'.format(exception_info.value))
  • 执行如下命令pytest -sv test_1.py::test_f2,两个冒号表示层级关系,可以通过此方式指定具体要执行的用例
  • 此时异常已经被捕获,用例正常通过
  • 同时可以看到打印出来的exception_info的属性
(venv) C:\测试文件夹\project\python\pytest_demo>pytest -sv test_1.py::test_f2
========================================== test session starts ===========================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-3
2\python.exe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                          
test_1.py::test_f2
error type is <class 'NameError'>
error typename is NameError
error message is name 'f2' is not defined
PASSED
=========================================== 1 passed in 0.01s ============================================

5. 上述例子是可预期的错误,或者说是故意制造的错误后并产生异常

  • 有时候用例可能因为功能没有实现,或者依赖项错误导致用例暂时失败,则需要用另外一种方式标记失败
@pytest.mark.xfail()
# param: reason 该用例当前失败的原因
# param: raises 声明用例失败是什么异常导致的,当该用例执行过程中抛出的异常和声明的不同时,该用例不会显示xfail,而是fail
@pytest.mark.xfail(reason='The function is not implemented', raises=NameError)
def test_f3():
    f3()

执行这条用例

(venv) C:\测试文件夹\project\python\pytest_demo>pytest -sv test_1.py::test_f3
==================================================================== test session starts =====================================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                                                                              
test_1.py::test_f3 XFAIL (The function is not implemented)
===================================================================== 1 xfailed in 0.04s =====================================================================

6. 为失败的断言定义你自己的解释

  • 可以通过实现pytest_assertrepr_compare钩子来添加自定义详细解释。
  • 先定义如下的Foo和测试用例
# content of test_foo_compare.py
class Foo:
    def __init__(self, val):
        self.val = val

    def __eq__(self, other):
        return self.val == other.val


def test_compare():
    f1 = Foo(1)
    f2 = Foo(2)
    assert f1 == f2
  • 先执行一次,现在使用的是默认的断言,展示的错误信息也是默认的
(venv) C:\测试文件夹\project\python\pytest_demo>pytest -sv test_foo_compare.py::test_compare
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                                                                                                                            

test_foo_compare.py::test_compare FAILED

================================================================================================= FAILURES =================================================================================================
_______________________________________________________________________________________________ test_compare _______________________________________________________________________________________________

    def test_compare():
        f1 = Foo(1)
        f2 = Foo(2)
>       assert f1 == f2
E       assert <test_foo_com...at 0x040EB310> == <test_foo_com...at 0x040EB2D0>
E         +<test_foo_compare.Foo object at 0x040EB310>
E         -<test_foo_compare.Foo object at 0x040EB2D0>

test_foo_compare.py:13: AssertionError
========================================================================================= short test summary info ==========================================================================================
FAILED test_foo_compare.py::test_compare - assert <test_foo_com...at 0x040EB310> == <test_foo_com...at 0x040EB2D0>
============================================================================================ 1 failed in 0.10s =============================================================================================
  • 在同级目录的conftest.py中定义钩子,来生成自定义比较的异常信息
  • op 表示断言的操作符
  • left 表示操作符左侧被比较的对象
  • right 表示操作符右侧被比较的对象
from test_foo_compare import Foo


def pytest_assertrepr_compare(op, left, right):
    if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
        return [
            "Comparing Foo instances:",
            "   vals: {} != {}".format(left.val, right.val),
        ]
  • 再次执行用例,断言已经变成自定义断言了,需要注意的是,此处断言仅仅是对两个Foo的等于生效,对其他的不生效
(venv) C:\测试文件夹\project\python\pytest_demo>pytest -sv test_foo_compare.py::test_compare
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- c:\program files (x86)\python36-32\python.exe
cachedir: .pytest_cache
rootdir: C:\测试文件夹\project\python\pytest_demo
collected 1 item                                                                                                                                                                                            

test_foo_compare.py::test_compare FAILED

================================================================================================= FAILURES =================================================================================================
_______________________________________________________________________________________________ test_compare _______________________________________________________________________________________________

    def test_compare():
        f1 = Foo(1)
        f2 = Foo(2)
>       assert f1 == f2
E       assert Comparing Foo instances:
E            vals: 1 != 2

test_foo_compare.py:13: AssertionError
========================================================================================= short test summary info ==========================================================================================
FAILED test_foo_compare.py::test_compare - assert Comparing Foo instances:
============================================================================================ 1 failed in 0.10s =============================================================================================

pytest Exception

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容