pytest(4):Pytest之斷言
阿新 • • 發佈:2021-07-22
什麼是斷言呢?簡單來說就是實際結果和期望結果去對比。
一斷言用法
在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;
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()
執行結果如下:
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 作為上下文管理器,當丟擲異常時可以獲取到對應的異常例項。
import pytest
def test_zero_division():
1 / 0
if __name__ == '__main__':
pytest.main()
執行結果:
================================== 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值。
斷言程式碼如下:
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 捕獲異常,原始碼如下:
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等屬性,原始碼如下:
@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的值是元組,所以要轉成字串。
自定義異常與pytest斷言結合
errors.py(格式唯一,一定要這麼寫)
class Exc(Exception):
def __init__(self,ErrorInfo):
super().__init__(self) #初始化父類
self.errorinfo=ErrorInfo
def __str__(self):
return self.errorinfo
testlogin2.py
import pytest
from pytestT.errors import Exc
from pytestT.errors import Exc2
class Test_login(object):
def f(self,a):
if a==1:
raise Exc('異常')
else:
raise Exc2
def test_T(self):
with pytest.raises(Exc) as F:
self.f(1)
print('***************')
# assert F.type==Exc
assert str(F.value)=='異常'
print('**************')
print(F.value)