pytest个人觉得很好用。但是有些功能老是忘记。 昨天全面扫描了以下官方文档,记录了一些东西,权且当作笔记吧。 官网地址: https://docs.pytest.org/en/latest/getting-started.html#run-multiple-tests
如果你不记得里面某个参数,可以用帮助命令来查看:
代码语言:javascript复制pytest --help
to see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
这里基本把所有的参数,都列出来了。
用例的选择
代码语言:javascript复制在模块中运行测试
pytest test_mod.py
在目录中运行测试
pytest testing/
按关键字表达式运行测试
pytest -k "MyClass and not method"
按节点ID运行测试
每个收集的测试都被分配一个唯一的 nodeid 它由模块文件名和诸如类名、函数名和参数化参数等说明符组成,用 :: 字符。
在模块内运行特定测试:
pytest test_mod.py::test_func
在命令行中指定测试方法的另一个示例:
pytest test_mod.py::TestClass::test_method
Run tests by marker expressions
pytest -m slow
将运行所有用 @pytest.mark.slow 装饰符。
标记多个
pytest -v test_server.py::TestClass test_server.py::test_send_http
我们现在可以使用 -m option 要选择一组:
$ pytest -m interface --tb=short
您还可以运行除与关键字匹配的测试以外的所有测试:
$ pytest -k "not send_http" -v
你可以使用 and , or , not 和括号
失败重跑
代码语言:javascript复制pytest--重复执行用例 pytest-repeat
使用pip安装pytest-repeat
pip install pytest-repeat
重复执行--count
命令行执行:pytest baidu/test_1_baidu.py -s --count=5
在代码中标记要重复多次的测试
@pytest.mark.repeat(1000)
在代码中标记要重复多次的测试
@pytest.mark.repeat(1000)
--repeat-scope
--repeat-scope类似于pytest fixture的scope参数,--repeat-scope也可以设置参数:session , module,class或者function(默认值)
function(默认)范围针对每个用例重复执行,再执行下一个用例
class 以class为用例集合单位,重复执行class里面的用例,再执行下一个
module 以模块为单位,重复执行模块里面的用例,再执行下一个
session 重复整个测试会话,即所有收集的测试执行一次,然后所有这些测试再次执行等等
使用--repeat-scope=session重复执行整个会话用例
如:pytest test_1_baidu.py -s --count=5 --repeat-scope=session
在第一(n)次失败后停止测试过程:
pytest -x # stop after first failure
pytest --maxfail=2 # stop after two failures
--lf , --last-failed -只重新运行故障
--ff , --failed-first -先运行失败,然后运行其余的测试。
断言:
代码语言:javascript复制pytest.raises(SystemExit)
def f():
return 3
def test_function():
a = f()
assert a % 2 == 0, "判断a为偶数,当前a的值为:%s"%a
assert xx 判断xx为真
assert not xx 判断xx不为真
assert a in b 判断b包含a
assert a == b 判断a等于b
assert a != b 判断a不等于b
assert hasattr(x, "check")
import pytest
def test_zero_division():
'''断言异常'''
with pytest.raises(ZeroDivisionError) as excinfo:
1 / 0
# 断言异常类型type
assert excinfo.type == ZeroDivisionError
# 断言异常value值
assert "division by zero" in str(excinfo.value)
异常:
代码语言:javascript复制excinfo 是一个异常信息实例,它是围绕实际引发的异常的包装器。主要属性是.type、 .value 和 .traceback
预期内异常
import pytest
def test_raises():
with pytest.raises(ZeroDivisionError):
2 / 0
assert eval("1 2") == 3
raises 可以捕获到该异常,并继续下面断言代码。
如果我们不知道预期异常的是什么,我们可以使用 match 和 raise 进行自定义异常
import pytest
def exc(x):
if x == 0:
raise ValueError("value not 0 or None")
return 2 / x
def test_raises():
with pytest.raises(ValueError, match="value not 0 or None"):
exc(0)
assert eval("1 2") == 3
match 还可以使用正则表达式进行匹配异常:
with pytest.raises(ValueError, match=r"value not d $"):
raise ValueError("value not 0")
Tips: 使用正则时,等号后面有个 r 。
在捕获异常后,可以从上下文管理器中获取异常的一些详细信息,可以辅助我们更好的去断言。
import pytest
def exc(x):
if x == 0:
raise ValueError("value not 0")
return 2 / x
def test_raises():
with pytest.raises(ValueError) as exec_info:
exc(0)
print("exec_info.type = ", exec_info.type)
print("exec_info.value.args = ", exec_info.value.args)
assert exec_info.type == ValueError
assert exec_info.value.args[0] == "value not 0"
动态添加标记
代码语言:javascript复制根据测试名称自动添加标记
如果您有一个测试套件,其中测试函数名表示某个测试类型,则可以实现一个自动定义标记的钩子,以便您可以使用 -m 选择它。让我们看看这个测试模块:
# content of test_module.py
def test_interface_simple():
assert 0
def test_interface_complex():
assert 0
def test_event_simple():
assert 0
def test_something_else():
assert 0
我们希望动态定义两个标记,并可以在 conftest.py 插件:
# content of conftest.py
import pytest
def pytest_collection_modifyitems(items):
for item in items:
if "interface" in item.nodeid:
item.add_marker(pytest.mark.interface)
elif "event" in item.nodeid:
item.add_marker(pytest.mark.event)
这东西,熟能生巧,如果不记得了,翻翻之前的文档看看,就可以快速重新用起来了。