文章目录
1、assert的各种使用场景
包含了几十种断言失败的各种场景,涉及断言的,可以查看pytest文档的 5.1.1(以 PDF 格式下载最新版本),举例几个常用的断言:
@pytest.mark.parametrize("param1, param2", [(3, 6)])
def test_generative(param1, param2):
assert param1 * 2 < param2
assert (3 * 2) < 6
def test_simple(self):
def f():
return 42
def g():
return 43
assert f() == g()
assert 42 == 43
def test_eq_long_text(self):
a = "1" * 100 + "a" + "2" * 100
b = "1" * 100 + "b" + "2" * 100
assert a == b
2、基本模式和示例
2.1 更改命令行选项的默认值
# content of pytest.ini
[pytest]
addopts = -ra -q
2.2 构建一个依赖于命令行选项的测试
根据命令行选项将不同的值传递给测试函数,运行用例:pytest -q test_sample.py --cmdopt=type3
# content of conftest.py
import pytest
def type_checker(value):
msg = "cmdopt must specify a numeric type as typeNNN"
if not value.startswith("type"):
raise pytest.UsageError(msg)
try:
int(value[4:])
except ValueError:
raise pytest.UsageError(msg)
return value
def pytest_addoption(parser):
parser.addoption(
"--cmdopt",
action="store",
default="type1",
help="my option: type1 or type2",
choices=("type1", "type2"),
type=type_checker,
)
@pytest.fixture
def cmdopt(request):
return request.config.getoption("--cmdopt")
# content of test_sample.py
def test_answer(cmdopt):
if cmdopt == "type1":
print("first")
elif cmdopt == "type2":
print("second")
assert 0
2.3 动态地添加命令行选项
# setuptools plugin
import sys
def pytest_load_initial_conftests(args):
if "xdist" in sys.modules: # pytest-xdist plugin
import multiprocessing
num = max(multiprocessing.cpu_count() / 2, 1)
args[:] = ["-n", str(num)] + args
2.4 控制跳过测试根据命令行选项
# content of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--runslow", action="store_true", default=False, help="run slow tests" )
def pytest_configure(config):
config.addinivalue_line("markers", "slow: mark test as slow to run")
def pytest_collection_modifyitems(config, items):
if config.getoption("--runslow"):
# --runslow given in cli: do not skip slow tests
return
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
for item in items:
if "slow" in item.keywords:
item.add_marker(skip_slow)
# content of test_module.py
import pytest
def test_func_fast():
pass
@pytest.mark.slow
def test_func_slow():
pass
2.5 编写良好的断言程序
# content of test_checkconfig.py
import pytest
def checkconfig(x):
__tracebackhide__ = True
if not hasattr(x, "config"):
pytest.fail("not configured: {}".format(x))
def test_something():
checkconfig(42)
2.6 检测是否从 pytest 运行中运行
# content of your_module.py
_called_from_test = False
# content of conftest.py
def pytest_configure(config):
your_module._called_from_test = True
2.7 向测试报告题头添加信息
# content of conftest.py
def pytest_report_header(config):
return "project deps: mylib-1.1"
2.8 分析测试持续时间
pytest --durations=3 test_some_are_slow.py
# content of test_some_are_slow.py
import time
def test_funcfast():
time.sleep(0.1)
def test_funcslow1():
time.sleep(0.2)
def test_funcslow2():
time.sleep(0.3)
2.11 处理过程后的测试报告/失败
# content of conftest.py
import pytest
import os.path
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
rep = outcome.get_result()
# we only look at actual failing test calls, not setup/teardown
if rep.when == "call" and rep.failed:
mode = "a" if os.path.exists("failures") else "w"
with open("failures", mode) as f:
# let's also access a fixture for the fun of it
if "tmp_path" in item.fixturenames:
extra = " ({})".format(item.funcargs["tmp_path"])
else:
extra = "" f.write(rep.nodeid + extra + "\n")
# content of test_module.py
def test_fail1(tmp_path):
assert 0
def test_fail2():
assert 0
2.12 在固定设备中提供测试结果信息
# content of conftest.py
import pytest
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
rep = outcome.get_result()
# set a report attribute for each phase of a call, which can
# be "setup", "call", "teardown"
setattr(item, "rep_" + rep.when, rep)
@pytest.fixture
def something(request):
yield
# request.node is an "item" because we use the default
# "function" scope
if request.node.rep_setup.failed:
print("setting up a test failed!", request.node.nodeid)
elif request.node.rep_setup.passed:
if request.node.rep_call.failed:
print(