Pytest之断言
在自动化测试过程中,需要判断预期结果和实际结果是否一致,这时需要使用到断言。
什么是断言呢?简单来说就是实际结果和期望结果去对比。
断言用法
在pytest中,使用assert进行断言,格式为:assert 表达式。
如果表达式返回结果为True,则断言成功,否则断言失败。
常用断言
unittest
的三种断言:
assertIn(expect,result)断言包含(被包含的写前面);
assertEqual(expect,result)断言相等;
assertTure(条件)断言是否为真。返回Ture或False;
Pytest
里的断言实际上就是Python中的assert断言方法,常用断言方法如下:
-
assert xx :判断 xx 为真;
-
assert not xx :判断 xx 不为真;
-
assert a in b :判断 b 包含 a;
-
assert a == b :判断 a 等于 b;
-
assert a != b :判断 a 不等于 b;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import pytest def test_demo1(): a = 1 assert a def test_demo2(): a = 0 assert not a def test_demo3(): s = 'hello' assert 'h' in s def test_demo4(): a = 3 assert a = = 3 def test_demo5(): a = 4 assert a ! = 3 if __name__ = = '__main__' : pytest.main() |
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Testing started at 18 : 22 ... C:\Users\ 96984 \Desktop\code\pytest\venv\Scripts\python.exe "C:\ruanjian\pycharm2019.3\PyCharm 2019.3.1\plugins\python\helpers\pycharm\_jb_pytest_runner.py" - - path C: / Users / 96984 / Desktop / code / pytest / demo / demo_pytest.py Launching pytest with arguments C: / Users / 96984 / Desktop / code / learn_pytest / demo / demo_pytest.py in C:\Users\ 96984 \Desktop\code\learn_pytest\demo = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test session starts = = = = = = = = = = = = = = = = = = = = = = = = = = = = = platform win32 - - Python 3.6 . 8 , pytest - 5.4 . 3 , py - 1.9 . 0 , pluggy - 0.13 . 1 - - C:\Users\ 96984 \Desktop\code\learn_pytest\venv\Scripts\python.exe cachedir: .pytest_cache metadata: { 'Python' : '3.6.8' , 'Platform' : 'Windows-10-10.0.18362-SP0' , 'Packages' : { 'pytest' : '5.4.3' , 'py' : '1.9.0' , 'pluggy' : '0.13.1' }, 'Plugins' : { 'html' : '2.1.1' , 'metadata' : '1.10.0' }, 'JAVA_HOME' : 'C:\\Program Files\\Java\\jdk1.8.0_77' } rootdir: C:\Users\ 96984 \Desktop\code\learn_pytest\demo plugins: html - 2.1 . 1 , metadata - 1.10 . 0 collecting ... collected 5 items demo_pytest.py::test_demo1 PASSED [ 20 % ] demo_pytest.py::test_demo2 PASSED [ 40 % ] demo_pytest.py::test_demo3 PASSED [ 60 % ] demo_pytest.py::test_demo4 PASSED [ 80 % ] demo_pytest.py::test_demo5 PASSED [ 100 % ] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 5 passed in 0.06s = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Process finished with exit code 0 |
异常断言
在测试过程中,有时需要对特定异常进行断言,可以使用 pytest.raises 作为上下文管理器,当抛出异常时可以获取到对应的异常实例。
1 2 3 4 5 | import pytest def test_zero_division(): 1 / 0 if __name__ = = '__main__' : pytest.main() |
运行结果:
1 2 3 4 5 | = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = FAILURES = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = _____________________________ test_zero_division ______________________________ def test_zero_division(): > 1 / 0 E ZeroDivisionError: division by zero |
所以我们需要捕获并断言异常。
断言场景:断言抛出的异常是否符合预期。
预期结果:ZeroDivisionError: division by zero,其中ZeroDivisionError为错误类型,division by zero为具体错误值。
断言方式: 断言异常的type和value值。
断言代码如下:
1 2 3 4 5 6 7 8 9 10 | import pytest def test_zero_division_long(): with pytest.raises(ZeroDivisionError) as excinfo: 1 / 0 # 断言异常类型 type assert excinfo. type = = ZeroDivisionError # 断言异常 value 值 assert "division by zero" in str (excinfo.value) if __name__ = = '__main__' : pytest.main() |
代码详细说明:
① pytest.raises 捕获异常,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | def raises( # noqa: F811 expected_exception: Union[ "Type[_E]" , Tuple [ "Type[_E]" , ...]], * args: Any , * * kwargs: Any ) - > Union[ "RaisesContext[_E]" , _pytest._code.ExceptionInfo[_E]]: __tracebackhide__ = True for exc in filterfalse( inspect.isclass, always_iterable(expected_exception, BASE_TYPE) # type: ignore[arg-type] # noqa: F821 ): msg = "exceptions must be derived from BaseException, not %s" raise TypeError(msg % type (exc)) message = "DID NOT RAISE {}" . format (expected_exception) if not args: match = kwargs.pop( "match" , None ) if kwargs: msg = "Unexpected keyword arguments passed to pytest.raises: " msg + = ", " .join( sorted (kwargs)) msg + = "\nUse context-manager form instead?" raise TypeError(msg) return RaisesContext(expected_exception, message, match) else : func = args[ 0 ] if not callable (func): raise TypeError( "{!r} object (type: {}) must be callable" . format (func, type (func)) ) try : func( * args[ 1 :], * * kwargs) except expected_exception as e: # We just caught the exception - there is a traceback. assert e.__traceback__ is not None return _pytest._code.ExceptionInfo.from_exc_info( ( type (e), e, e.__traceback__) ) fail(message) raises.Exception = fail.Exception # type: ignore |
② excinfo作为异常信息实例,拥有type 、value等属性,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @property def type ( self ) - > "Type[_E]" : """the exception class""" assert ( self ._excinfo is not None ), ".type can only be used after the context manager exits" return self ._excinfo[ 0 ] @property def value( self ) - > _E: """the exception value""" assert ( self ._excinfo is not None ), ".value can only be used after the context manager exits" return self ._excinfo[ 1 ] |
③ excinfo.value的值是元组,所以要转成字符串。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?