上一章学习了pytest的基本用法,今天学习一下断言。
assert 基本用法
unitest单元测试框架中提供了丰富的断言方法,如assertEqual()、assertIn()、assertTrue()、assertIs()等,但是pytest
没有。直接使用Python的assert
进行断言
# 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
,用法如下:
# 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
非预期内异常
如果我们不知道预期异常的是什么,我们可以使用match
和raise
进行自定义异常
# 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
在第一个断言失败的情况下继续执行后续的断言,不会终止~