• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

pytest之assert断言的具体使用

python 搞代码 4年前 (2022-01-08) 16次浏览 已收录 0个评论

这篇文章主要介绍了pytest之assert断言的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

背景

本文总结使用pytest编写自动化测试时常用的assert断言。

说明

本文将从以下几点做总结:

  1. 为测试结果作断言
  2. 为断言不通过的结果添加说明信息
  3. 为预期异常作断言
  4. 为失败断言自定义说明信息

为测试结果作断言

在断言方面,pytest框架比其他类似的框架(比如unittest)更加简洁,易用,我想这是我选择pytest作为自动化测试框架之一的原因之一。
pytest的assert断言关键字支持使用python内置的assert表达式。可以理解为pytest的断言就是直接使用python自带的assert关键字。

python assert的概念:

Python assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常。

我们可以在在assert后面添加任何符合python标准的表达式,如果表达式的值通过bool转换后等于False,则意味着断言结果为失败。

以下举例常用的表达式:

 # ./test_case/test_func.py import pytest from func import * class TestFunc: def test_add_by_class(self): assert add(2,3) == 5 def test_add_by_func_aaa(): assert 'a' in 'abc' assert 'a' not in 'bbc' something = True assert something something = False assert not something assert 1==1 assert 1!=2 assert 'a' is 'a' assert 'a' is not 'b' assert 1  1 assert 1 = 1 assert add(3,3) == 6 ''' # 以上全是合法的表达式且表达式的值都为True,所以测试结果为通过 ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 2 items test_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%] test_case/test_func.py::test_add_by_func_aaa PASSED                      [100%] ============================== 2 passed in 0.06s ============================== [Finished in 1.8s] '''

为断言不通过的结果添加说明信息

在编写测试时,为了提高易用性,我们想知道断言失败时的一些关于失败的原因等说明信息,assert也能满足该功能。
请看示例:

 # ./test_case/test_func.py import pytest from func import * class TestFunc: def test_add_by_class(self): assert add(2,3) == 5 def test_add_by_func_aaa(): assert add(3,3) == 5, "3+3应该等于6" ''' ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 2 items test_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%] test_case/test_func.py::test_add_by_func_aaa FAILED                      [100%] ================================== FAILURES =================================== ____________________________ test_add_by_func_aaa _____________________________ def test_add_by_func_aaa(): >    assert add(3,3) == 5, "3+3应该等于6" E    AssertionError: 3+3应该等于6 E    assert 6 == 5 E      -6 E      +5 test_case\test_func.py:14: AssertionError ========================= 1 failed, 1 passed in 0.09s ========================= [Finished in 1.4s] '''

为预期异常作断言

在某些测试用例中,比如异常测试用例,测试的结果必然是失败并应该爆出异常的。这时候自动化测试用例的期望结果就是该异常。如果期望结果等于该异常,那么测试用例执行通过,否则用例结果为失败。pytest提供为为预期异常作断言的方法:pytest.raises()。一般结合with上下文管理器使用。

使用示例:

 # ./func.py def add(a,b): if isinstance(a,int) and isinstance(b,int): return a+b else: raise NameError('数据类型错误') # ./test_case/test_func.py import pytest from func import * class TestFunc: # 正常测试用例 def test_add_by_class(self): assert add(2,3) == 5 # 异常测试用例,期望结果为爆出TypeError异常 def test_add_by_func_aaa(): with pytest.raises(TypeError): add('3',4) # ./run_test.py import pytest if __name__ == '__main__': pytest.main(['-v']) ''' ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 2 items test_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%] test_case/test_func.py::test_add_by_func_aaa PASSED                      [100%] ============================== 2 passed in 0.06s ============================== [Finished in 1.4s] ''' 

接下来看看没有爆出预期异常的示例:

 # ./func.py def add(a,b): # 指定异常 raise NameError("天降异常") if isinstance(a,int) and isinstance(b,int): return a+b else: raise NameError('数据类型错误') # ./test_case/test_func.py import pytest from func import * ''' class TestFunc: # 正常测试用例 def test_add_by_class(self): assert add(2,3) == 5 ''' # 异常测试用例,期望结果为爆出TypeError异常 def test_add_by_func_aaa(): with pytest.raises(TypeError): add('3',4) # ./run_test.py import pytest if __name__ == '__main__': pytest.main(['-v']) ''' ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 1 item test_case/test_func.py::test_add_by_func_aaa FAILED                      [100%] ================================== FAILURES =================================== ____________________________ test_add_by_func_aaa _____________________________ def test_add_by_func_aaa(): with pytest.raises(TypeError): >     add('3',4) test_case\test_func.py:14: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ a = '3', b = 4 def add(a,b): # 指定异常 >    raise NameError("天降异常") E    NameError: 天降异常 func.py:4: NameError ============================== 1 failed in 0.09s ============================== [Finished in 1.4s] '''

判定用例执行结果为失败。

上面我们只是断言了异常的类型。但有的时候我们想更进一步断言异常的说明信息,pytest也可以做到。with pytest.raises()执行结束后会生成一个ExceptionInfo的实例对象。该对象包含type , value, traceback属性。value属性就是我们需要的异常说明信息。

见示例:

 # ./func.py def add(a,b): if isinstance(a,int) and isinstance(b,int): return a+b else: raise TypeError('数据类型错误') # ./test_case/test_func.py import pytest from func import * class TestFunc: # 正常测试用例 def test_add_by_class(self): assert add(2,3) == 5 # 异常测试用例,期望结果为爆出TypeError异常 def test_add_by_func_aaa(): with pytest.raises(TypeError) as E: add('3',4) print(E.type) print(E.value) print(E.traceback) # 加入该不通过断言为了查看stdout assert 1 == 2 # ./run_test.py import pytest if __name__ == '__main__': pytest.main(['-v']) ''' ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 2 items test_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%] test_case/test_func.py::test_add_by_func_aaa FAILED                      [100%] ================================== FAILURES =================================== ____________________________ test_add_by_func_aaa _____________________________ def test_add_by_func_aaa(): with pytest.raises(TypeError) as E: add('3',4) print(E.type) print(E.value) print(E.traceback) >    assert 1 == 2 E    assert 1 == 2 E      -1 E      +2 test_case\test_func.py:18: AssertionError ---------------------------- Captured stdout call -----------------------------  数据类型错误 [, ] ========================= 1 failed, 1 passed in 0.10s ========================= <span style="color:transparent">来源gaodai#ma#com搞*!代#%^码网</span>[Finished in 1.4s] '''

控制台输出的“Captured stdout call”就是异常的信息,包含类型,异常说明,异常跟踪信息。
可以通过assert断言这些信息。

也可以通过给pytest.raises()传入match关键字参数来完成E.value的断言,这里运用到的是python中正则表达式的原理。

示例:

该示例意味断言通过

 def test_add_by_func_aaa(): with pytest.raises(TypeError, match=r'.*类型错误$') as E: add('3',4) 

该示例意味断言失败:

 # 异常测试用例,期望结果为爆出TypeError异常 def test_add_by_func_aaa(): with pytest.raises(TypeError, match=r'.*正确$') as E: add('3',4) ''' During handling of the above exception, another exception occurred: def test_add_by_func_aaa(): with pytest.raises(TypeError, match=r'.*正确$') as E: >     add('3',4) E     AssertionError: Pattern '.*正确$' not found in '数据类型错误' test_case\test_func.py:14: AssertionError '''

如果,某个测试用例可能出现不同的预期异常,只要爆出的异常在预期的几个异常之内,那么如何断言呢。解决方法很简单,原理和接口都没变,只是在pytest.raises()中传入异常类型的参数,从传入一个异常类型,改变为传入一个异常类型组成的元组。同样只是传入一个参数。

示例:

 # ./func.py def add(a,b): raise NameError('名字错了') if isinstance(a,int) and isinstance(b,int): return a+b else: raise TypeError('数据类型错误') # ./test_case/test_func.py import pytest from func import * ''' class TestFunc: # 正常测试用例 def test_add_by_class(self): assert add(2,3) == 5 ''' # 异常测试用例,期望结果为爆出TypeError异常 def test_add_by_func_aaa(): with pytest.raises((TypeError,NameError),match=r'.*错.*$') as E: add('3',4) # ./run_test.py import pytest if __name__ == '__main__': pytest.main(['-v']) ''' ============================= test session starts ============================= platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe cachedir: .pytest_cache rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini plugins: allure-pytest-2.8.9, rerunfailures-8.0 collecting ... collected 1 item test_case/test_func.py::test_add_by_func_aaa PASSED                      [100%] ============================== 1 passed in 0.04s ============================== [Finished in 1.4s] '''

为失败断言自定义说明信息

这种行为,相当于改变了pytest的运行方式,虽然只是一种锦上添花的改变。我们通过编写hook函数来改变pytest的行为。hook函数是pytest提供的,有很多,各个hook函数的详细定义应该参考pytest的官方文档。
为失败断言自定义说明信息是通过pytest_assertrepr_compare这个hook函数完成的。
先看没有编写pytest_assertrepr_compare这个hook函数时,默认的失败断言说明:

 def test_add_by_func_aaa(): assert 'aaa' == 'bbb' ''' ================================== FAILURES =================================== ____________________________ test_add_by_func_aaa _____________________________ def test_add_by_func_aaa(): >    assert 'aaa' == 'bbb' E    AssertionError: assert 'aaa' == 'bbb' E      - aaa E      + bbb test_case\test_func.py:16: AssertionError '''

再看编写pytest_assertrepr_compare这个hook函数后:

 # ./conftest.py def pytest_assertrepr_compare(op, left, right): if isinstance(left, str) and isinstance(right, str) and op == "==": return ['两个字符串比较:', '   值: %s != %s' % (left, right)] # ./test_case/test_func.py import pytest def test_add_by_func_aaa(): assert 'aaa' == 'bbb' ''' .F                                                                       [100%] ================================== FAILURES =================================== ____________________________ test_add_by_func_aaa _____________________________ def test_add_by_func_aaa(): >    assert 'aaa' == 'bbb' E    assert 两个字符串比较: E         值: aaa != bbb test_case\test_func.py:15: AssertionError 1 failed, 1 passed in 0.09s [Finished in 1.5s] '''

pytest还提供其他的hook函数,这些函数的作用就是用来改变pytest的运行方式和运行效果。所以编写第三方插件一般是使用这些hook函数。

以上就是pytest之assert断言的具体使用的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:pytest之assert断言的具体使用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址