单元测试框架:针对最小单位(函数、方法)进行的正确性检查测试。
pytest可以和selenium、requests、appium结合实现web自动化、接口自动化、app自动化。
默认用例编写规则
1、module必须以test_开头或test_结尾(.py)
2、测试类必须以Test开头,并且不能有__init__方法
3、测试方法(函数)必须以test开头(def)
如何调用pytest
使用pytest命令,会执行当前目录及其子目录中所有文件名以test_*.py或\*_test.py形式结尾的文件中的所有测试。
Pytest支持从命令行运行和选择测试的几种方法
指定运行模块:pytest test_login.py
指定运行目录:pytest -vs interface
指定运行用例:pytest -vs interface/test_ilogin.py::test_04
指定带特定参数:pytest tests/test_mod.py::test_func[x1,y2]
按关键字表达式运行测试:-k (不区分大小写)
获取关于版本、选项名、环境变量的帮助
版本:pytest --version
可用的内置函数参数:pytest --fixtures
环境变量的帮助:pytest -h | --help
分析测试执行时间
注:默认情况下,pytest不会显示太小(<0.005s)的测试持续时间,除非在命令行上传递-vv
管理插件的加载
加载插件:pytest -p plugin_name
禁用插件:pytest -p no:plugin_name
如何在测试中编写和报告断言
assert + 表达式
表达式为True,则断言成功,否则断言失败。
断言函数与后边的值进行比较,一致则测试通过,否则失败。
assert x: 判断x为真;
assert not x:判断x不为真;
assert a in b:判断b包含a;
assert a == b:判断a等于b;
assert a!= b:判断a不等于b。
def f():
return 3
def test_f():
assert f() == 4
"""
FAILED [100%]
cha2.py:8 (test_f)
3 != 4
Expected :4
Actual :3
<Click to see difference>
def test_f():
> assert f() == 4
E assert 3 == 4
E + where 3 = f()
cha2.py:10: AssertionError
"""
关于预期异常的断言
使用pytest.raise()作为上下文管理器:
- 可以捕获特定的异常(预期内异常)
- 获取捕获的异常的细节(异常类型,异常信息)
- 发生异常,后面的代码将正常执行
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
"""
============================= test session starts =============================
collecting ... collected 1 item
cha2.py::test_zero_division PASSED [100%]
============================== 1 passed in 0.01s ==============================
"""
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
assert 3 == 2
"""
============================= test session starts =============================
collecting ... collected 1 item
cha2.py::test_zero_division FAILED [100%]
cha2.py:12 (test_zero_division)
3 != 2
Expected :2
Actual :3
<Click to see difference>
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
> assert 3 == 2
E assert 3 == 2
cha2.py:16: AssertionError
============================== 1 failed in 0.03s ==============================
"""
将with后边表达式的值存到as后的变量(元组)中。
确保在代码块执行完毕后正确地释放资源。
上下文管理器:__enter__和__exit__。
excinfo是一个ExceptionInfo实例,它是对实际引发的异常的包装,属性包括type、value、traceback。
def test_re_depth():
with pytest.raises(RuntimeError) as excinfo:
def f1():
f1()
f1()
assert "maximum recursion" in str(excinfo)
"""
============================= test session starts =============================
collecting ... collected 1 item
cha2.py::test_re_depth PASSED [100%]
============================== 1 passed in 0.01s ==============================
"""
def test_foo_not_implemented():
def foo():
raise NotImplementedError
with pytest.raises(RuntimeError) as excinfo:
foo()
assert excinfo.type is RuntimeError
# NotImplementedError是RuntimeError的子类
"""
============================= test session starts =============================
collecting ... collected 1 item
cha2.py::test_foo_not_implemented FAILED [100%]
cha2.py:26 (test_foo_not_implemented)
<class 'NotImplementedError'> != <class 'RuntimeError'>
Expected :<class 'RuntimeError'>
Actual :<class 'NotImplementedError'>
<Click to see difference>
def test_foo_not_implemented():
def foo():
raise NotImplementedError
with pytest.raises(RuntimeError) as excinfo:
foo()
> assert excinfo.type is RuntimeError
E AssertionError: assert <class 'NotImplementedError'> is RuntimeError
E + where <class 'NotImplementedError'> = <ExceptionInfo NotImplementedError() tblen=2>.type
cha2.py:32: AssertionError
============================== 1 failed in 0.03s ==============================
"""
匹配异常消息
使用match关键字参数传递给上下文管理器,以测试正则表达式是否匹配异常的字符串表示。
正则表达式:包含字符串“123”,必须加“r”。
def myfunc():
raise ValueError("Exception 123 raised")
def test_match():
with pytest.raises(ValueError, match=r".*123.*"):
myfunc()
"""
============================= test session starts =============================
collecting ... collected 1 item
cha2.py::test_match PASSED [100%]
============================== 1 passed in 0.01s ==============================
"""